1 Introduction

1.1 Using This Dataset

The purpose of using this data set is to build models that predict student academic success. However, a significant challenge associated with this endeavor is the strong class imbalance in the data, as described by the authors in “Early Prediction of student’s Performance in Higher Education: A Case Study.” The goal of this report is to use exploratory data analysis to examine the features closely correlated with student academic performance, as measured by first- and second-semester grade average. Understanding these relationships may help inform the development of machine learning models that more accurately predict academic success while mitigating bias.

1.2 Description of Data

This dataset contains features provided by a higher education institution in Portugal and collected from various disjoint databases about students at the time of their enrollment in an undergraduate degree program. The purpose of the dataset is to predict student dropout and academic success. The features relate to student demographics, socio-economic indicators, degree program, and academic performance at the end of the first and second semesters. The collected data previously underwent cleaning.

1.3 List of Features

The dataset contains 4,424 observations and 34 feature variables.

  • Marital Status (categorical): 6 categories include single, married, widower, divorced, de facto union, or legally separated; 88.6% of students are categorized as single.
  • Application mode (categorical): 18 categories include information related to the student’s application classifiers, such as international student, special contingent, special age category, and transfer student.
  • Application order (categorical): 8 categories of preferred application order between first choice and last choice.
  • Course (categorical): 17 categories for chosen course of study.
  • Daytime/evening attendance (binary): Whether a student attends during the day or in the evening; 89.08% attend during the day.
  • Previous Qualification (categorical): 17 categories of highest education level, from secondary education to master’s degree; 84.02% of students completed their secondary education (12th year of schooling or equivalent).
  • Nationality (categorical): 21 nationalities represented, 97.5% Portuguese and the remaining international students.
  • Mother’s Qualification and Father’s Qualification (categorical): 29 and 34 categories of highest education level, respectively.
  • Mother’s Occupation and Father’s Occupation (categorical): 32 and 46 categories of occupation, respectively.
  • Displaced (binary): Whether or not a student is displaced; 54.84% of students are displaced.
  • Educational special needs (binary): 1.15% of students reported educational special needs.
  • Debtor (binary): Whether or not a student has debt; 11.37% of students have debt.
  • Tuition fees up to date (binary): Whether or not a student’s tuition fees are up to date; 11.93% are not up-to-date on their payments.
  • Gender (binary): 64.83% of students are female
  • Scholarship holder (binary): 24.84% of students hold a scholarship.
  • Age at enrollment (integer): Age of the student when they are enrolled; 64.94% are 21 years old or younger.
  • International student (binary): International students (i.e., not from Portugal) account for 2.49% of the sample.
  • Curricular Units 1st Semester and Curricular Units 2nd Semester (integers): Number of curricular units Credited, Enrolled, and Approved for each semester. Evaluations encompasses the number of evaluations to curricular units in each semester, and Without Evaluations is the number of curricular units without evaluations in each semester. Grade is the average grade between 0 and 20 per semester.
  • Economic variables (continuous): This dataset includes continuous variables related to the Unemployment Rate, Inflation Rate, and GDP.
  • Target (categorical): A student’s academic outcome: Dropout, graduate, enrolled.
data <- read.csv("https://christinekillion.github.io/machine_learning/data/student-success.csv")

# Change column names
colnames(data) <- c(
  "Marital", "Application_M", "Application_O", "Course", 
  "Attendance", "S_Qual", "Nationality", 
  "M_Qual", "F_Qual", "M_Occ", 
  "F_Occ", "Displaced", "Special_Needs", "Debtor", 
  "Tuition", "Gender", "Scholarship", "Age", 
  "International", "U_Credited1", "U_Enrolled1",
  "U_Evaluated1", "U_Approved1", 
  "Grade1", "U_WO_Eval1", 
  "U_Credited2", "U_Enrolled2", 
  "U_Evaluated2", "U_Approved2", 
  "Grade2", "U_WO_Eval2", 
  "Unemployment", "Inflation", "GDP", "Target"
)

# Create random observation ID and replace 8% of the corresponding observations with missing values 
grades1.missing.id <- sample(1:4424, 353, replace = FALSE)
grades2.missing.id <- sample(1:4424, 354, replace = FALSE) 
data$Grade1[grades1.missing.id] <- NA
data$Grade2[grades2.missing.id] <- NA

#Total the number of missing values per column.
missing_per_column <- colSums(is.na(data))

#Total the number of missing values in the dataset. 
total_missing <- sum(is.na(data))

2 Distribution of Individual Features

This section will describe the univariate distributions of the key categorical, dichotomous, and continuous features in the dataset and analyze any potential issues for machine learning applications.

2.1 Student Groups of Interest

There are three key groups that are underrepresented within this dataset and should be carefully considered in the development of machine learning models so as not to reproduce bias. Section 3 of this report explores in more detail the relationship between these groups and academic achievement in the dataset.

# Count the number of occurrences for each category
debtor_counts <- table(data$Debtor)
tuition_counts <- table(data$Tuition)
gender_counts <- table(data$Gender)

# Create data frames from the counts for each category
debtor_df <- as.data.frame(debtor_counts)
tuition_df <- as.data.frame(tuition_counts)
gender_df <- as.data.frame(gender_counts)

# Recode binary values from numbers to categories 
debtor_df$Var1 <- recode(debtor_df$Var1, `1` = "Debt", `0` = "No Debt")
tuition_df$Var1 <- recode(tuition_df$Var1, `1` = "Paid", `0` = "Unpaid")
gender_df$Var1 <- recode(gender_df$Var1, `1` = "Male", `0` = "Female")

# Create the pie charts with ggplot2

# Debtor Pie Chart
pie_debtor <- ggplot(debtor_df, aes(x = "", y = Freq, fill = Var1)) +
  geom_bar(stat = "identity", width = 1) + 
  coord_polar(theta = "y") +  # Convert bar chart to pie chart
  scale_fill_manual(values = c("#4C57B8", "#AFB1F0")) +
  theme_void() +  # Remove background and axes
  guides(fill = guide_legend(title = NULL)) +  # Add legend and remove title
  ggtitle("Debtor Status")  # Remove individual title

# Tuition Fees Pie Chart
pie_tuition <- ggplot(tuition_df, aes(x = "", y = Freq, fill = Var1)) +
  geom_bar(stat = "identity", width = 1) + 
  coord_polar(theta = "y") +  # Convert bar chart to pie chart
  scale_fill_manual(values = c("#F5A1B5", "#ac1f67")) +
  theme_void() +  # Remove background and axes
  guides(fill = guide_legend(title = NULL)) +  # Add legend and remove title
  ggtitle("Tuition Fees")  # Remove individual title

# Gender Pie Chart
pie_gender <- ggplot(gender_df, aes(x = "", y = Freq, fill = Var1)) +
  geom_bar(stat = "identity", width = 1) + 
  coord_polar(theta = "y") +  # Convert bar chart to pie chart
  scale_fill_manual(values = c("#E6DE3C", "#B9A520")) +
  theme_void() +  # Remove background and axes
  guides(fill = guide_legend(title = NULL)) +  # Add legend and remove title
  ggtitle("Gender")  

# Combine the pie charts into a grid with a centered main title
grid.arrange(
  pie_debtor, pie_tuition, pie_gender, 
  ncol = 3, 
  heights = unit(c(1, 0.1), "npc")  # Allocate space for the legends
)

2.2 Parental Education

This dataset contains the previous academic qualifications of the student, mother, and father. For students, 84.02% have completed secondary education. The parental qualification distributions do not reflect that of the students: There is a wider range of educational categories for each of the parent groups (likely due to the disparate sources of data). When recoded and grouped into three main categories (secondary education, higher education, and other), the distribution of parent qualifications in the dataset indicates that most of the parent qualifications fall into the “other” category. More recoding is required to classify qualifications in order to examine the relationship between parent qualification and student grades.

# Create a dataframe with 4 rows and 34 columns. First column is Var1, 1:34
qual <- data.frame(matrix(1:34, nrow = 34, ncol = 1))
colnames(qual) <- c("Var1")

# Calculate the count of each category
S_qual <- data.frame(table(data$S_Qual))
M_qual <- data.frame(table(data$M_Qual))
F_qual <- data.frame(table(data$F_Qual))

# Merge by the common column "Var1"
qual <- merge(qual, S_qual, by = "Var1", all=TRUE)
qual <- merge(qual, M_qual, by = "Var1", all=TRUE)
qual <- merge(qual, F_qual, by = "Var1", all=TRUE)

colnames(qual) <- c("Qualification", "Student", "Mother", "Father")

# Replace NAs with 0
qual[is.na(qual)] <- 0
# Pivot the data to long format
qual_long <- qual %>%
  pivot_longer(cols = c(Student, Mother, Father), 
               names_to = "Role", 
               values_to = "Count")

# Filter for only Mother and Father roles
qual_long <- qual_long %>%
  filter(Role %in% c("Mother", "Father"))

# Group and rename the 'Qualification' categories
qual_long <- qual_long %>%
  mutate(Qualification = case_when(
    Qualification == 1 ~ "Secondary Education",
    Qualification >= 2 & Qualification <= 6 ~ "Higher Education Degree",
    Qualification >= 7 & Qualification <= 34 ~ "Other",
    TRUE ~ as.character(Qualification)  # In case there are any NA or unrecognized values
  ))

# Aggregate the data by Qualification and Role to get total count
qual_long_aggregated <- qual_long %>%
  group_by(Qualification, Role) %>%
  summarise(TotalCount = sum(Count), .groups = 'drop')

# Create the ggplot object for stacked bar plot
p <- ggplot(qual_long_aggregated, aes(x = Qualification, y = TotalCount, fill = Role, text = paste("Total Count: ", TotalCount))) +
  geom_bar(stat = "identity") +  # Use stat="identity" to use the actual counts
  labs(x = "Qualification", y = "Count", fill = "Role") +
  ggtitle("Distribution of Parent Qualifications (Grouped by Education Level)") +  # Add title here
scale_fill_manual(values = c("Mother" = "#FFC20A", "Father" = "#0C7BDC")) +  # Set custom colors
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

# Convert the ggplot object to a plotly object for interactivity
interactive_plot <- ggplotly(p, tooltip = "text")

# Show the interactive plot
interactive_plot

2.3 Grade Distribution

The grade features for each semester contain both missing values and values of zero. When grades of zero are excluded, the grade distributions are approximately normally distributed. Data imputation could replace the missing values, or another binary feature can be created to retain the information of students with a grade of zero for each semester.

# Remove grades of zero
first_semester_grades <- data$Grade1[data$Grade1 != 0]
second_semester_grades <- data$Grade2[data$Grade2 != 0]

# Plot for first semester
gradeplot1 <- ggplot(data.frame(grade = first_semester_grades), aes(x = grade)) +
  geom_histogram(aes(y = ..density..), bins = 10, fill = "#ac1f67", color = "black", alpha = 0.7) +
  stat_function(fun = dnorm, args = list(mean = mean(first_semester_grades), sd = sd(first_semester_grades)), color = "red", size = 1) +
  labs(title = "First Semester Grades", x = "Grades", y = "Density") +
  theme_minimal()

# Plot for second semester
gradeplot2 <- ggplot(data.frame(grade = second_semester_grades), aes(x = grade)) +
  geom_histogram(aes(y = ..density..), bins = 10, fill = "#ac1f67", color = "black", alpha = 0.7) +
  stat_function(fun = dnorm, args = list(mean = mean(second_semester_grades), sd = sd(second_semester_grades)), color = "blue", size = 1) +
  labs(title = "Second Semester Grades", x = "Grades", y = "Density") +
  theme_minimal()

# Arrange the two plots side by side
grid.arrange(gradeplot1, gradeplot2, ncol = 2)

3 Relationship Between Features

This section examines the relationships between key categorical and numerical features in the dataset.

3.1 Grade Averages

Grade average in the first semester and second semester appear to have a positive linear relationship. Based on this model, for every one-unit increase in first semester grade average, we expect to see a 0.7 increase in second-semester grade average.

# Remove rows where Grade1 or Grade2 is zero
filtered_data <- data[data$Grade1 != 0 & data$Grade2 != 0, ]

# Fit a linear regression model
model <- lm(Grade2 ~ Grade1, data = filtered_data)

# Scatterplot of first-semester and second-semester average grades
plot(filtered_data$Grade1, filtered_data$Grade2,
     col = "#FFC20A",
     pch = 19, 
     main = "Average Grades",
     xlab = "First Semester",
     ylab = "Second Semester")

# Add the regression line
abline(model, col = "black", lwd = 2)  # Red regression line with thickness of 2

# coefficient of Grade1
slope <- coef(model)[2]

3.2 Grades and Finances

A minority of students have debt or unpaid tuition fees. In the figure below, the distribution of average grades is stratified by debt status and also by tuition status. The students in the minority for these categories appear to have a lower grade distribution. At the 0.05 significance level, there is sufficient evidence to conclude that the mean average grades differ significantly between these majority and minority groups. Analytic tasks will include removing or imputating grade values of zero, then re-examining the relationship.

3.2.0.1 Distribution of Average Grades by Debtor Status

col0 = c("#FFC20A", "#0C7BDC")

# Set up layout for the boxplots
par(mfrow = c(1, 2))  # 1 rows, 2 columns

# Create two boxplots
boxplot(data$Grade1 ~ data$Debtor, 
        col = c("#FFC20A", "#0C7BDC"),
        main = "First Semester",
        xlab = " ",
        ylab = "Average Grade",
        cex.axis = 0.9,  # Smaller font size for axis labels
        cex.lab = 0.9)   # Smaller font size for axis titles

boxplot(data$Grade2 ~ data$Debtor,
        col = c("#FFC20A", "#0C7BDC"),
        main = "Second Semester",
        xlab = " ",
        ylab = " ",
        cex.axis = 0.9,  # Smaller font size for axis labels
        cex.lab = 0.9)   # Smaller font size for axis titles

3.2.0.2 Distribution of Average Grades by Tuition Status

col1 = c("#0C7BDC", "#FFC20A")

# Set up layout for the boxplots
par(mfrow = c(1, 2))  # 1 rows, 2 columns

boxplot(data$Grade1 ~ data$Tuition, 
        col = col1,
        main = "First Semester",
        xlab = " ",
        ylab = "Average Grade",
        cex.axis = 0.9,  # Smaller font size for axis labels
        cex.lab = 0.9)   # Smaller font size for axis titles
boxplot(data$Grade2 ~ data$Tuition, 
        col = col1,
        main = "Second Semester",
        xlab = " ",
        ylab = " ",
        cex.axis = 0.9,  # Smaller font size for axis labels
        cex.lab = 0.9)   # Smaller font size for axis titles

# T test between categorical variable and continuous variable
invisible(t.test(data$Grade1 ~ data$Debtor, data = data))
invisible(t.test(data$Grade2 ~ data$Debtor, data = data))
# T test between categorical variable and continuous variable
invisible(t.test(data$Grade1 ~ data$Tuition, data = data))
invisible(t.test(data$Grade2 ~ data$Tuition, data = data))

3.3 Grades and Gender

Male students, accounting for 35.17% of the dataset, appear to achieve a lower average grade distribution. There is enough evidence to indicate a significant difference between this group’s mean average grade and that of female students at the 0.05 significance level. Analytic tasks will include removing or imputating grade values of zero, then re-examining the relationship.

3.3.0.1 Distribution of Average Grades by Gender

col1 = c("#0C7BDC", "#FFC20A")

# Set up layout for the boxplots
par(mfrow = c(1, 2))  # 1 rows, 2 columns

boxplot(data$Grade1 ~ data$Gender, 
        col = col1,
        main = "First Semester",
        xlab = " ",
        ylab = "Average Grade",
        cex.axis = 0.9,  # Smaller font size for axis labels
        cex.lab = 0.9)   # Smaller font size for axis titles
boxplot(data$Grade2 ~ data$Gender, 
        col = col1,
        main = "Second Semester",
        xlab = " ",
        ylab = " ",
        cex.axis = 0.9,  # Smaller font size for axis labels
        cex.lab = 0.9)   # Smaller font size for axis titles

# T test between categorical variable and continuous variable
invisible(t.test(data$Grade1 ~ data$Gender, data = data))
invisible(t.test(data$Grade2 ~ data$Gender, data = data))

3.4 Curricular Units

This dataset includes multiple variables measuring credits for each semester: number of curricular units credited, enrolled, and approved. A significant number of the credited variables for each semester have a value of zero, more so in the second semester; this may indicate that the information was recorded before the end of the second semester and may be incomplete. For this reason, we might consider only including approved curricular units as a potential variable in our model.

sem1_approved <- data$U_Approved1
sem1_enrolled <- data$U_Enrolled1
sem1_credited <- data$U_Credited1

# Count frequencies of credits for each variable for the first semester
sem1_approved_counts <- as.data.frame(table(sem1_approved))
sem1_enrolled_counts <- as.data.frame(table(sem1_enrolled))
sem1_credited_counts <- as.data.frame(table(sem1_credited))

# Create bar plots for the first semester
plot1 <- ggplot(sem1_approved_counts, aes(x = sem1_approved, y = Freq)) +
  geom_bar(stat = "identity", fill = "#ac1f67", color = "black", alpha = 0.7) +
  labs(title = " ", x = "Credits Approved", y = "Number of Occurrences") +  
  theme_minimal() +
  theme(axis.text.x = element_blank())

plot2 <- ggplot(sem1_enrolled_counts, aes(x = sem1_enrolled, y = Freq)) +
  geom_bar(stat = "identity", fill = "#0C7BDC", color = "black", alpha = 0.7) +
  labs(title = "First Semester", x = "Credits Enrolled", y = " ") +
  theme_minimal() +
  theme(axis.text.x = element_blank())

plot3 <- ggplot(sem1_credited_counts, aes(x = sem1_credited, y = Freq)) +
  geom_bar(stat = "identity", fill = "#FFC20A", color = "black", alpha = 0.7) +
  labs(title = " ", x = "Credited Units", y = " ") +
  theme_minimal() +
  theme(axis.text.x = element_blank())

# Arrange the plots side by side for the first semester
grid.arrange(plot1, plot2, plot3, ncol = 3)

sem2_approved <- data$U_Approved2
sem2_enrolled <- data$U_Enrolled2
sem2_credited <- data$U_Credited2

# Count frequencies of credits for each variable for the second semester
sem2_approved_counts <- as.data.frame(table(sem2_approved))
sem2_enrolled_counts <- as.data.frame(table(sem2_enrolled))
sem2_credited_counts <- as.data.frame(table(sem2_credited))

# Create bar plots for the second semester
plot1_2nd <- ggplot(sem2_approved_counts, aes(x = sem2_approved, y = Freq)) +
  geom_bar(stat = "identity", fill = "#ac1f67", color = "black", alpha = 0.7) +
  labs(title = " ", x = "Credits Approved", y = "Number of Occurrences") +
  theme_minimal() +
  theme(axis.text.x = element_blank())

plot2_2nd <- ggplot(sem2_enrolled_counts, aes(x = sem2_enrolled, y = Freq)) +
  geom_bar(stat = "identity", fill = "#0C7BDC", color = "black", alpha = 0.7) +
  labs(title = "Second Semester", x = "Credits Enrolled", y = " ") +
  theme_minimal() +
  theme(axis.text.x = element_blank())

plot3_2nd <- ggplot(sem2_credited_counts, aes(x = sem2_credited, y = Freq)) +
  geom_bar(stat = "identity", fill = "#FFC20A", color = "black", alpha = 0.7) +
  labs(title = " ", x = "Credited Units", y = " ") +
  theme_minimal() +
  theme(axis.text.x = element_blank())

# Arrange the plots side by side for the second semester
grid.arrange(plot1_2nd, plot2_2nd, plot3_2nd, ncol = 3)

3.5 Stratifying Grades by Curricular Unit Group

Based on the boxplots for grades stratified by the curricular unit approved group, it appears that students with between 4 and 8 curricular units approved achieve significantly higher grades than those with fewer than 4 and slightly higher grades on average than those more than 8.

# Create Unit_Group1 based on U_Approved1
data$Unit_Group1 <- cut(data$U_Approved1, 
                        breaks = c(-Inf, 0, 3, 8, Inf), 
                        labels = c("0", "1-3", "4-8", "9+"),
                        right = TRUE)

# Create Unit_Group2 based on U_Approved2
data$Unit_Group2 <- cut(data$U_Approved2, 
                        breaks = c(-Inf, 0, 3, 8, Inf), 
                        labels = c("0", "1-3", "4-8", "9+"),
                        right = TRUE)
col2 = c("#FFC20A", "#0C7BDC", "#ac1f67")

# Filter out "0" group from both Unit_Group1 and Unit_Group2
data_filtered1 <- data[data$Unit_Group1 != "0", ]
data_filtered2 <- data[data$Unit_Group2 != "0", ]

# Set up layout for the boxplots
par(mfrow = c(1, 2))  # 1 row, 2 columns

# Create the first boxplot for the first semester, excluding "0" group
boxplot(data_filtered1$Grade1 ~ data_filtered1$Unit_Group1, 
        col = col2,
        main = "First Semester",
        xlab = " ",
        ylab = "Average Grade",
        cex.axis = 0.9,  # Smaller font size for axis labels
        cex.lab = 0.9)   # Smaller font size for axis titles

# Create the second boxplot for the second semester, excluding "0" group
boxplot(data_filtered2$Grade2 ~ data_filtered2$Unit_Group2,
        col = col2,
        main = "Second Semester",
        xlab = " ",
        ylab = " ",
        cex.axis = 0.9,  # Smaller font size for axis labels
        cex.lab = 0.9)   # Smaller font size for axis titles

Note a similar trend for the number of evaluations to curricular units.

# Create Eval_Group1 based on U_Evaluated1
data$Eval_Group1 <- cut(data$U_Evaluated1, 
                        breaks = c(-Inf, 0, 4, 10, Inf), 
                        labels = c("0", "1-4", "5-10", "11+"),
                        right = TRUE)

# Create Eval_Group2 based on U_Evaluated2
data$Eval_Group2 <- cut(data$U_Evaluated2, 
                        breaks = c(-Inf, 0, 4, 10, Inf), 
                        labels = c("0", "1-4", "5-10", "11+"),
                        right = TRUE)
col3 = c("#FFC20A", "#0C7BDC", "#ac1f67", "#AFB1F0")

# Set up layout for the boxplots
par(mfrow = c(1, 2))  # 1 row, 2 columns

# Create the first boxplot for the first semester
boxplot(data$Grade1 ~ data$Eval_Group1, 
        col = col3,
        main = "First Semester",
        xlab = "Evaluations",
        ylab = "Average Grade",
        cex.axis = 0.9,  # Smaller font size for axis labels
        cex.lab = 0.9)   # Smaller font size for axis titles

# Create the second boxplot for the second semester
boxplot(data$Grade2 ~ data$Eval_Group2,
        col = col3,
        main = "Second Semester",
        xlab = " ",
        ylab = " ",
        cex.axis = 0.9,  # Smaller font size for axis labels
        cex.lab = 0.9)   # Smaller font size for axis titles

4 References

DATA: M.V.Martins, D. Tolledo, J. Machado, L. M.T. Baptista, V.Realinho. (2021). Predict Students’ Dropout and Academic Success. Kaggle. Attribution 4.0 International (CC BY 4.0). https://www.kaggle.com/datasets/harshitsrivastava25/predict-students-dropout-and-academic-success/data

LS0tCnRpdGxlOiAiRXhhbWluaW5nIFJlbGF0aW9uc2hpcHMgQmV0d2VlbiBTb2Npb2Vjb25vbWljIEZhY3RvcnMgYW5kIEFjYWRlbWljIFBlcmZvcm1hbmNlIHRvIEltcHJvdmUgUHJlZGljdGl2ZSBNb2RlbHMgb2YgU3R1ZGVudCBTdWNjZXNzIgphdXRob3I6ICJDaHJpc3RpbmUgS2lsbGlvbiIKZGF0ZTogIlVwZGF0ZWQgRmVicnVhcnkgMTgsIDIwMjUiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OiAKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDQKICAgIHRvY19mbG9hdDogeWVzCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogICAgdG9jX2NvbGxhcHNlZDogeWVzCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIGNvZGVfZG93bmxvYWQ6IHllcwogICAgc21vb3RoX3Njcm9sbDogeWVzCiAgICB0aGVtZTogbHVtZW4KICB3b3JkX2RvY3VtZW50OiAKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDQKICAgIGZpZ19jYXB0aW9uOiB5ZXMKICAgIGtlZXBfbWQ6IHllcwogIHBkZl9kb2N1bWVudDogCiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiA0CiAgICBmaWdfY2FwdGlvbjogeWVzCiAgICBudW1iZXJfc2VjdGlvbnM6IG5vCiAgICBmaWdfd2lkdGg6IDMKICAgIGZpZ19oZWlnaHQ6IDMKZWRpdG9yX29wdGlvbnM6IAogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUKLS0tCgpgYGB7PWh0bWx9Cgo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgoKLyogQ2FzY2FkaW5nIFN0eWxlIFNoZWV0cyAoQ1NTKSBpcyBhIHN0eWxlc2hlZXQgbGFuZ3VhZ2UgdXNlZCB0byBkZXNjcmliZSB0aGUgcHJlc2VudGF0aW9uIG9mIGEgZG9jdW1lbnQgd3JpdHRlbiBpbiBIVE1MIG9yIFhNTC4gaXQgaXMgYSBzaW1wbGUgbWVjaGFuaXNtIGZvciBhZGRpbmcgc3R5bGUgKGUuZy4sIGZvbnRzLCBjb2xvcnMsIHNwYWNpbmcpIHRvIFdlYiBkb2N1bWVudHMuICovCgpoMS50aXRsZSB7ICAvKiBUaXRsZSAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgb2YgdGhlIHJlcG9ydCB0aXRsZSAqLwogIGZvbnQtc2l6ZTogMjJweDsKICBmb250LXdlaWdodDogYm9sZDsKICBjb2xvcjogI2FjMWY2NzsKICB0ZXh0LWFsaWduOiBjZW50ZXI7CiAgZm9udC1mYW1pbHk6IHNhbnMtc2VyaWY7Cn0KaDQuYXV0aG9yIHsgLyogSGVhZGVyIDQgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciBhdXRob3JzICAqLwogIGZvbnQtc2l6ZTogMThweDsKICBmb250LWZhbWlseTogc3lzdGVtLXVpOwogIGNvbG9yOiBuYXZ5OwogIHRleHQtYWxpZ246IGNlbnRlcjsKICBmb250LXdlaWdodDogc3Ryb25nOwp9Cmg0LmRhdGUgeyAvKiBIZWFkZXIgNCAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgZm9yIHRoZSBkYXRlICAqLwogIGZvbnQtc2l6ZTogMTJweDsKICBmb250LWZhbWlseTogc3lzdGVtLXVpOwogIGNvbG9yOiBuYXZ5OwogIHRleHQtYWxpZ246IGNlbnRlcjsKICBmb250LXdlaWdodDogbm9ybWFsOwp9CmgxIHsgLyogSGVhZGVyIDEgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciBsZXZlbCAxIHNlY3Rpb24gdGl0bGUgICovCiAgICBmb250LXNpemU6IDIycHg7CiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICAgIGNvbG9yOiBuYXZ5OwogICAgdGV4dC1hbGlnbjogY2VudGVyOwogICAgZm9udC13ZWlnaHQ6IGJvbGQ7Cn0KaDIgeyAvKiBIZWFkZXIgMiAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgZm9yIGxldmVsIDIgc2VjdGlvbiB0aXRsZSAqLwogICAgZm9udC1zaXplOiAyMHB4OwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogbmF2eTsKICAgIHRleHQtYWxpZ246IGxlZnQ7CiAgICBmb250LXdlaWdodDogYm9sZDsKfQoKaDMgeyAvKiBIZWFkZXIgMyAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgb2YgbGV2ZWwgMyBzZWN0aW9uIHRpdGxlICAqLwogICAgZm9udC1zaXplOiAxOHB4OwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogbmF2eTsKICAgIHRleHQtYWxpZ246IGxlZnQ7Cn0KCmg0IHsgLyogSGVhZGVyIDQgLSBmb250IHNwZWNpZmljYXRpb25zIG9mIGxldmVsIDQgc2VjdGlvbiB0aXRsZSAgKi8KICAgIGZvbnQtc2l6ZTogMThweDsKICAgIGZvbnQtd2VpZ2h0OiBib2xkOwogICAgZm9udC1mYW1pbHk6IHNhbnMtc2VyaWY7CiAgICBjb2xvcjogYmxhY2s7CiAgICB0ZXh0LWFsaWduOiBjZW50ZXI7Cn0KCmJvZHkgeyBiYWNrZ3JvdW5kLWNvbG9yOndoaXRlOyB9CgouaGlnaGxpZ2h0bWUgeyBiYWNrZ3JvdW5kLWNvbG9yOnllbGxvdzsgfQoKcCB7IGJhY2tncm91bmQtY29sb3I6d2hpdGU7IH0KCjwvc3R5bGU+CmBgYAoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CiMgY29kZSBjaHVuayBzcGVjaWZpZXMgd2hldGhlciB0aGUgUiBjb2RlLCB3YXJuaW5ncywgYW5kIG91dHB1dCAKIyB3aWxsIGJlIGluY2x1ZGVkIGluIHRoZSBvdXRwdXQgZmlsZXMuCmlmICghcmVxdWlyZSgia25pdHIiKSkgewogICBpbnN0YWxsLnBhY2thZ2VzKCJrbml0ciIpCiAgIGxpYnJhcnkoa25pdHIpCn0KaWYgKCFyZXF1aXJlKCJ0aWR5dmVyc2UiKSkgewogICBpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKfQppZiAoIXJlcXVpcmUoInBhbG1lcnBlbmd1aW5zIikpIHsKICAgaW5zdGFsbC5wYWNrYWdlcygicGFsbWVycGVuZ3VpbnMiKQpsaWJyYXJ5KHBhbG1lcnBlbmd1aW5zKQp9CmlmICghcmVxdWlyZSgicGxvdGx5IikpIHsKICAgaW5zdGFsbC5wYWNrYWdlcygicGxvdGx5IikKbGlicmFyeShwbG90bHkpCn0KaWYgKCFyZXF1aXJlKCJHR2FsbHkiKSkgewogICBpbnN0YWxsLnBhY2thZ2VzKCJHR2FsbHkiKQpsaWJyYXJ5KEdHYWxseSkKfQppZiAoIXJlcXVpcmUoIm5hbmlhciIpKSB7CiAgIGluc3RhbGwucGFja2FnZXMoIm5hbmlhciIpCmxpYnJhcnkobmFuaWFyKQp9CmlmICghcmVxdWlyZSgicG9vbCIpKSB7CiAgIGluc3RhbGwucGFja2FnZXMoInBvb2wiKQpsaWJyYXJ5KHBvb2wpCn0KaWYgKCFyZXF1aXJlKCJEQkkiKSkgewogICBpbnN0YWxsLnBhY2thZ2VzKCJEQkkiKQpsaWJyYXJ5KERCSSkKfQppZiAoIXJlcXVpcmUoIlJNeVNRTCIpKSB7CiAgIGluc3RhbGwucGFja2FnZXMoIlJNeVNRTCIpCmxpYnJhcnkoUk15U1FMKQp9CmlmICghcmVxdWlyZSgicmFuZG9tRm9yZXN0IikpIHsKICAgaW5zdGFsbC5wYWNrYWdlcygicmFuZG9tRm9yZXN0IikKbGlicmFyeShyYW5kb21Gb3Jlc3QpCn0KaWYgKCFyZXF1aXJlKCJnZ2lyYXBoIikpIHsKICAgaW5zdGFsbC5wYWNrYWdlcygiZ2dpcmFwaCIpCmxpYnJhcnkoZ2dpcmFwaCkKfQppZiAoIXJlcXVpcmUoImhpZ2hjaGFydGVyIikpIHsKICAgaW5zdGFsbC5wYWNrYWdlcygiaGlnaGNoYXJ0ZXIiKQpsaWJyYXJ5KGhpZ2hjaGFydGVyKQp9CmlmICghcmVxdWlyZSgiYnJvb20iKSkgewogICBpbnN0YWxsLnBhY2thZ2VzKCJicm9vbSIpCmxpYnJhcnkoYnJvb20pCn0KaWYgKCFyZXF1aXJlKCJtaWNlIikpIHsKICAgaW5zdGFsbC5wYWNrYWdlcygibWljZSIpCmxpYnJhcnkobWljZSkKfQppZiAoIXJlcXVpcmUoImdncGxvdDIiKSkgewogICBpbnN0YWxsLnBhY2thZ2VzKCJnZ3Bsb3QyIikKbGlicmFyeShnZ3Bsb3QyKQp9CmlmICghcmVxdWlyZSgiZHBseXIiKSkgewogICBpbnN0YWxsLnBhY2thZ2VzKCJkcGx5ciIpCmxpYnJhcnkoZHBseXIpCn0KaWYgKCFyZXF1aXJlKCJncmlkRXh0cmEiKSkgewogICBpbnN0YWxsLnBhY2thZ2VzKCJncmlkRXh0cmEiKQpsaWJyYXJ5KGdyaWRFeHRyYSkKfQppZiAoIXJlcXVpcmUoInRpZHlyIikpIHsKICAgaW5zdGFsbC5wYWNrYWdlcygidGlkeXIiKQpsaWJyYXJ5KHRpZHlyKQp9CmlmICghcmVxdWlyZSgibWljZSIpKSB7CiAgIGluc3RhbGwucGFja2FnZXMoIm1pY2UiKQpsaWJyYXJ5KG1pY2UpCn0KCgojIyAKa25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCAgICMgaW5jbHVkZSBjb2RlIGNodW5rIGluIHRoZSBvdXRwdXQgZmlsZQogICAgICAgICAgICAgICAgICAgICAgd2FybmluZyA9IEZBTFNFLCMgc29tZXRpbWVzLCB5b3UgY29kZSBtYXkgcHJvZHVjZSB3YXJuaW5nIG1lc3NhZ2VzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgeW91IGNhbiBjaG9vc2UgdG8gaW5jbHVkZSB0aGUgd2FybmluZyBtZXNzYWdlcyBpbgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdGhlIG91dHB1dCBmaWxlLiAKICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdHMgPSBUUlVFLCAjIHlvdSBjYW4gYWxzbyBkZWNpZGUgd2hldGhlciB0byBpbmNsdWRlIHRoZSBvdXRwdXQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGluIHRoZSBvdXRwdXQgZmlsZS4KICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgIGNvbW1lbnQgPSBOQQogICAgICAgICAgICAgICAgICAgICAgKSAgCmBgYAoKIyAgSW50cm9kdWN0aW9uCgojIyAgVXNpbmcgVGhpcyBEYXRhc2V0IAoKVGhlIHB1cnBvc2Ugb2YgdXNpbmcgdGhpcyBkYXRhIHNldCBpcyB0byBidWlsZCBtb2RlbHMgdGhhdCBwcmVkaWN0IHN0dWRlbnQgYWNhZGVtaWMgc3VjY2Vzcy4gSG93ZXZlciwgYSBzaWduaWZpY2FudCBjaGFsbGVuZ2UgYXNzb2NpYXRlZCB3aXRoIHRoaXMgZW5kZWF2b3IgaXMgdGhlIHN0cm9uZyBjbGFzcyBpbWJhbGFuY2UgaW4gdGhlIGRhdGEsIGFzIGRlc2NyaWJlZCBieSB0aGUgYXV0aG9ycyBpbiAiRWFybHkgUHJlZGljdGlvbiBvZiBzdHVkZW504oCZcyBQZXJmb3JtYW5jZSBpbiBIaWdoZXIgRWR1Y2F0aW9uOiBBIENhc2UgU3R1ZHkuIiBUaGUgZ29hbCBvZiB0aGlzIHJlcG9ydCBpcyB0byB1c2UgZXhwbG9yYXRvcnkgZGF0YSBhbmFseXNpcyB0byBleGFtaW5lIHRoZSBmZWF0dXJlcyBjbG9zZWx5IGNvcnJlbGF0ZWQgd2l0aCBzdHVkZW50IGFjYWRlbWljIHBlcmZvcm1hbmNlLCBhcyBtZWFzdXJlZCBieSBmaXJzdC0gYW5kIHNlY29uZC1zZW1lc3RlciBncmFkZSBhdmVyYWdlLiBVbmRlcnN0YW5kaW5nIHRoZXNlIHJlbGF0aW9uc2hpcHMgbWF5IGhlbHAgaW5mb3JtIHRoZSBkZXZlbG9wbWVudCBvZiBtYWNoaW5lIGxlYXJuaW5nIG1vZGVscyB0aGF0IG1vcmUgYWNjdXJhdGVseSBwcmVkaWN0IGFjYWRlbWljIHN1Y2Nlc3Mgd2hpbGUgbWl0aWdhdGluZyBiaWFzLiAKCiMjICBEZXNjcmlwdGlvbiBvZiBEYXRhIAoKVGhpcyBkYXRhc2V0IGNvbnRhaW5zIGZlYXR1cmVzIHByb3ZpZGVkIGJ5IGEgaGlnaGVyIGVkdWNhdGlvbiBpbnN0aXR1dGlvbiBpbiBQb3J0dWdhbCBhbmQgY29sbGVjdGVkIGZyb20gdmFyaW91cyBkaXNqb2ludCBkYXRhYmFzZXMgYWJvdXQgc3R1ZGVudHMgYXQgdGhlIHRpbWUgb2YgdGhlaXIgZW5yb2xsbWVudCBpbiBhbiB1bmRlcmdyYWR1YXRlIGRlZ3JlZSBwcm9ncmFtLiBUaGUgcHVycG9zZSBvZiB0aGUgZGF0YXNldCBpcyB0byBwcmVkaWN0IHN0dWRlbnQgZHJvcG91dCBhbmQgYWNhZGVtaWMgc3VjY2Vzcy4gVGhlIGZlYXR1cmVzIHJlbGF0ZSB0byBzdHVkZW50IGRlbW9ncmFwaGljcywgc29jaW8tZWNvbm9taWMgaW5kaWNhdG9ycywgZGVncmVlIHByb2dyYW0sIGFuZCBhY2FkZW1pYyBwZXJmb3JtYW5jZSBhdCB0aGUgZW5kIG9mIHRoZSBmaXJzdCBhbmQgc2Vjb25kIHNlbWVzdGVycy4gVGhlIGNvbGxlY3RlZCBkYXRhIHByZXZpb3VzbHkgdW5kZXJ3ZW50IGNsZWFuaW5nLiAKCiMjICBMaXN0IG9mIEZlYXR1cmVzCgpUaGUgZGF0YXNldCBjb250YWlucyA0LDQyNCBvYnNlcnZhdGlvbnMgYW5kIDM0IGZlYXR1cmUgdmFyaWFibGVzLiAKCi0gKipNYXJpdGFsIFN0YXR1cyoqIChjYXRlZ29yaWNhbCk6IDYgY2F0ZWdvcmllcyBpbmNsdWRlIHNpbmdsZSwgbWFycmllZCwgd2lkb3dlciwgZGl2b3JjZWQsIGRlIGZhY3RvIHVuaW9uLCBvciBsZWdhbGx5IHNlcGFyYXRlZDsgODguNiUgb2Ygc3R1ZGVudHMgYXJlIGNhdGVnb3JpemVkIGFzIHNpbmdsZS4KLSAqKkFwcGxpY2F0aW9uIG1vZGUqKiAoY2F0ZWdvcmljYWwpOiAxOCBjYXRlZ29yaWVzIGluY2x1ZGUgaW5mb3JtYXRpb24gcmVsYXRlZCB0byB0aGUgc3R1ZGVudCdzIGFwcGxpY2F0aW9uIGNsYXNzaWZpZXJzLCBzdWNoIGFzIGludGVybmF0aW9uYWwgc3R1ZGVudCwgc3BlY2lhbCBjb250aW5nZW50LCBzcGVjaWFsIGFnZSBjYXRlZ29yeSwgYW5kIHRyYW5zZmVyIHN0dWRlbnQuCi0gKipBcHBsaWNhdGlvbiBvcmRlcioqIChjYXRlZ29yaWNhbCk6IDggY2F0ZWdvcmllcyBvZiBwcmVmZXJyZWQgYXBwbGljYXRpb24gb3JkZXIgYmV0d2VlbiBmaXJzdCBjaG9pY2UgYW5kIGxhc3QgY2hvaWNlLgotICoqQ291cnNlKiogKGNhdGVnb3JpY2FsKTogMTcgY2F0ZWdvcmllcyBmb3IgY2hvc2VuIGNvdXJzZSBvZiBzdHVkeS4KLSAqKkRheXRpbWUvZXZlbmluZyBhdHRlbmRhbmNlKiogKGJpbmFyeSk6IFdoZXRoZXIgYSBzdHVkZW50IGF0dGVuZHMgZHVyaW5nIHRoZSBkYXkgb3IgaW4gdGhlIGV2ZW5pbmc7IDg5LjA4JSBhdHRlbmQgZHVyaW5nIHRoZSBkYXkuIAotICoqUHJldmlvdXMgUXVhbGlmaWNhdGlvbioqIChjYXRlZ29yaWNhbCk6IDE3IGNhdGVnb3JpZXMgb2YgaGlnaGVzdCBlZHVjYXRpb24gbGV2ZWwsIGZyb20gc2Vjb25kYXJ5IGVkdWNhdGlvbiB0byBtYXN0ZXIncyBkZWdyZWU7IDg0LjAyJSBvZiBzdHVkZW50cyBjb21wbGV0ZWQgdGhlaXIgc2Vjb25kYXJ5IGVkdWNhdGlvbiAoMTJ0aCB5ZWFyIG9mIHNjaG9vbGluZyBvciBlcXVpdmFsZW50KS4KLSAqKk5hdGlvbmFsaXR5KiogKGNhdGVnb3JpY2FsKTogMjEgbmF0aW9uYWxpdGllcyByZXByZXNlbnRlZCwgOTcuNSUgUG9ydHVndWVzZSBhbmQgdGhlIHJlbWFpbmluZyBpbnRlcm5hdGlvbmFsIHN0dWRlbnRzLiAKLSAqKk1vdGhlcidzIFF1YWxpZmljYXRpb24qKiBhbmQgKipGYXRoZXIncyBRdWFsaWZpY2F0aW9uKiogKGNhdGVnb3JpY2FsKTogMjkgYW5kIDM0IGNhdGVnb3JpZXMgb2YgaGlnaGVzdCBlZHVjYXRpb24gbGV2ZWwsIHJlc3BlY3RpdmVseS4gCi0gKipNb3RoZXIncyBPY2N1cGF0aW9uKiogYW5kICoqRmF0aGVyJ3MgT2NjdXBhdGlvbioqIChjYXRlZ29yaWNhbCk6IDMyIGFuZCA0NiBjYXRlZ29yaWVzIG9mIG9jY3VwYXRpb24sIHJlc3BlY3RpdmVseS4gCi0gKipEaXNwbGFjZWQqKiAoYmluYXJ5KTogV2hldGhlciBvciBub3QgYSBzdHVkZW50IGlzIGRpc3BsYWNlZDsgNTQuODQlIG9mIHN0dWRlbnRzIGFyZSBkaXNwbGFjZWQuIAotICoqRWR1Y2F0aW9uYWwgc3BlY2lhbCBuZWVkcyoqIChiaW5hcnkpOiAxLjE1JSBvZiBzdHVkZW50cyByZXBvcnRlZCBlZHVjYXRpb25hbCBzcGVjaWFsIG5lZWRzLgotICoqRGVidG9yKiogKGJpbmFyeSk6IFdoZXRoZXIgb3Igbm90IGEgc3R1ZGVudCBoYXMgZGVidDsgMTEuMzclIG9mIHN0dWRlbnRzIGhhdmUgZGVidC4KLSAqKlR1aXRpb24gZmVlcyB1cCB0byBkYXRlKiogKGJpbmFyeSk6IFdoZXRoZXIgb3Igbm90IGEgc3R1ZGVudCdzIHR1aXRpb24gZmVlcyBhcmUgdXAgdG8gZGF0ZTsgMTEuOTMlIGFyZSBub3QgdXAtdG8tZGF0ZSBvbiB0aGVpciBwYXltZW50cy4gCi0gKipHZW5kZXIqKiAoYmluYXJ5KTogNjQuODMlIG9mIHN0dWRlbnRzIGFyZSBmZW1hbGUgCi0gKipTY2hvbGFyc2hpcCBob2xkZXIqKiAoYmluYXJ5KTogMjQuODQlIG9mIHN0dWRlbnRzIGhvbGQgYSBzY2hvbGFyc2hpcC4gCi0gKipBZ2UgYXQgZW5yb2xsbWVudCoqIChpbnRlZ2VyKTogQWdlIG9mIHRoZSBzdHVkZW50IHdoZW4gdGhleSBhcmUgZW5yb2xsZWQ7IDY0Ljk0JSBhcmUgMjEgeWVhcnMgb2xkIG9yIHlvdW5nZXIuIAotICoqSW50ZXJuYXRpb25hbCBzdHVkZW50KiogKGJpbmFyeSk6IEludGVybmF0aW9uYWwgc3R1ZGVudHMgKGkuZS4sIG5vdCBmcm9tIFBvcnR1Z2FsKSBhY2NvdW50IGZvciAyLjQ5JSBvZiB0aGUgc2FtcGxlLiAKLSAqKkN1cnJpY3VsYXIgVW5pdHMgMXN0IFNlbWVzdGVyKiogYW5kICoqQ3VycmljdWxhciBVbml0cyAybmQgU2VtZXN0ZXIqKiAoaW50ZWdlcnMpOiBOdW1iZXIgb2YgY3VycmljdWxhciB1bml0cyAqKkNyZWRpdGVkKiosICoqRW5yb2xsZWQqKiwgYW5kICoqQXBwcm92ZWQqKiBmb3IgZWFjaCBzZW1lc3Rlci4gKipFdmFsdWF0aW9ucyoqIGVuY29tcGFzc2VzIHRoZSBudW1iZXIgb2YgZXZhbHVhdGlvbnMgdG8gY3VycmljdWxhciB1bml0cyBpbiBlYWNoIHNlbWVzdGVyLCBhbmQgKipXaXRob3V0IEV2YWx1YXRpb25zKiogaXMgdGhlIG51bWJlciBvZiBjdXJyaWN1bGFyIHVuaXRzIHdpdGhvdXQgZXZhbHVhdGlvbnMgaW4gZWFjaCBzZW1lc3Rlci4gKipHcmFkZSoqIGlzIHRoZSBhdmVyYWdlIGdyYWRlIGJldHdlZW4gMCBhbmQgMjAgcGVyIHNlbWVzdGVyLgotIEVjb25vbWljIHZhcmlhYmxlcyAoY29udGludW91cyk6IFRoaXMgZGF0YXNldCBpbmNsdWRlcyBjb250aW51b3VzIHZhcmlhYmxlcyByZWxhdGVkIHRvIHRoZSAqKlVuZW1wbG95bWVudCBSYXRlKiosICoqSW5mbGF0aW9uIFJhdGUqKiwgYW5kICoqR0RQKiouCi0gKipUYXJnZXQqKiAoY2F0ZWdvcmljYWwpOiBBIHN0dWRlbnQncyBhY2FkZW1pYyBvdXRjb21lOiBEcm9wb3V0LCBncmFkdWF0ZSwgZW5yb2xsZWQuIAoKYGBge3IgZGF0YX0KZGF0YSA8LSByZWFkLmNzdigiaHR0cHM6Ly9jaHJpc3RpbmVraWxsaW9uLmdpdGh1Yi5pby9tYWNoaW5lX2xlYXJuaW5nL2RhdGEvc3R1ZGVudC1zdWNjZXNzLmNzdiIpCgojIENoYW5nZSBjb2x1bW4gbmFtZXMKY29sbmFtZXMoZGF0YSkgPC0gYygKICAiTWFyaXRhbCIsICJBcHBsaWNhdGlvbl9NIiwgIkFwcGxpY2F0aW9uX08iLCAiQ291cnNlIiwgCiAgIkF0dGVuZGFuY2UiLCAiU19RdWFsIiwgIk5hdGlvbmFsaXR5IiwgCiAgIk1fUXVhbCIsICJGX1F1YWwiLCAiTV9PY2MiLCAKICAiRl9PY2MiLCAiRGlzcGxhY2VkIiwgIlNwZWNpYWxfTmVlZHMiLCAiRGVidG9yIiwgCiAgIlR1aXRpb24iLCAiR2VuZGVyIiwgIlNjaG9sYXJzaGlwIiwgIkFnZSIsIAogICJJbnRlcm5hdGlvbmFsIiwgIlVfQ3JlZGl0ZWQxIiwgIlVfRW5yb2xsZWQxIiwKICAiVV9FdmFsdWF0ZWQxIiwgIlVfQXBwcm92ZWQxIiwgCiAgIkdyYWRlMSIsICJVX1dPX0V2YWwxIiwgCiAgIlVfQ3JlZGl0ZWQyIiwgIlVfRW5yb2xsZWQyIiwgCiAgIlVfRXZhbHVhdGVkMiIsICJVX0FwcHJvdmVkMiIsIAogICJHcmFkZTIiLCAiVV9XT19FdmFsMiIsIAogICJVbmVtcGxveW1lbnQiLCAiSW5mbGF0aW9uIiwgIkdEUCIsICJUYXJnZXQiCikKCiMgQ3JlYXRlIHJhbmRvbSBvYnNlcnZhdGlvbiBJRCBhbmQgcmVwbGFjZSA4JSBvZiB0aGUgY29ycmVzcG9uZGluZyBvYnNlcnZhdGlvbnMgd2l0aCBtaXNzaW5nIHZhbHVlcyAKZ3JhZGVzMS5taXNzaW5nLmlkIDwtIHNhbXBsZSgxOjQ0MjQsIDM1MywgcmVwbGFjZSA9IEZBTFNFKQpncmFkZXMyLm1pc3NpbmcuaWQgPC0gc2FtcGxlKDE6NDQyNCwgMzU0LCByZXBsYWNlID0gRkFMU0UpIApkYXRhJEdyYWRlMVtncmFkZXMxLm1pc3NpbmcuaWRdIDwtIE5BCmRhdGEkR3JhZGUyW2dyYWRlczIubWlzc2luZy5pZF0gPC0gTkEKCiNUb3RhbCB0aGUgbnVtYmVyIG9mIG1pc3NpbmcgdmFsdWVzIHBlciBjb2x1bW4uCm1pc3NpbmdfcGVyX2NvbHVtbiA8LSBjb2xTdW1zKGlzLm5hKGRhdGEpKQoKI1RvdGFsIHRoZSBudW1iZXIgb2YgbWlzc2luZyB2YWx1ZXMgaW4gdGhlIGRhdGFzZXQuIAp0b3RhbF9taXNzaW5nIDwtIHN1bShpcy5uYShkYXRhKSkKYGBgCgojICBEaXN0cmlidXRpb24gb2YgSW5kaXZpZHVhbCBGZWF0dXJlcyAKClRoaXMgc2VjdGlvbiB3aWxsIGRlc2NyaWJlIHRoZSB1bml2YXJpYXRlIGRpc3RyaWJ1dGlvbnMgb2YgdGhlIGtleSBjYXRlZ29yaWNhbCwgZGljaG90b21vdXMsIGFuZCBjb250aW51b3VzIGZlYXR1cmVzIGluIHRoZSBkYXRhc2V0IGFuZCBhbmFseXplIGFueSBwb3RlbnRpYWwgaXNzdWVzIGZvciBtYWNoaW5lIGxlYXJuaW5nIGFwcGxpY2F0aW9ucy4gCgojIyBTdHVkZW50IEdyb3VwcyBvZiBJbnRlcmVzdCAKClRoZXJlIGFyZSB0aHJlZSBrZXkgZ3JvdXBzIHRoYXQgYXJlIHVuZGVycmVwcmVzZW50ZWQgd2l0aGluIHRoaXMgZGF0YXNldCBhbmQgc2hvdWxkIGJlIGNhcmVmdWxseSBjb25zaWRlcmVkIGluIHRoZSBkZXZlbG9wbWVudCBvZiBtYWNoaW5lIGxlYXJuaW5nIG1vZGVscyBzbyBhcyBub3QgdG8gcmVwcm9kdWNlIGJpYXMuIFNlY3Rpb24gMyBvZiB0aGlzIHJlcG9ydCBleHBsb3JlcyBpbiBtb3JlIGRldGFpbCB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlc2UgZ3JvdXBzIGFuZCBhY2FkZW1pYyBhY2hpZXZlbWVudCBpbiB0aGUgZGF0YXNldC4gCgpgYGB7cn0KIyBDb3VudCB0aGUgbnVtYmVyIG9mIG9jY3VycmVuY2VzIGZvciBlYWNoIGNhdGVnb3J5CmRlYnRvcl9jb3VudHMgPC0gdGFibGUoZGF0YSREZWJ0b3IpCnR1aXRpb25fY291bnRzIDwtIHRhYmxlKGRhdGEkVHVpdGlvbikKZ2VuZGVyX2NvdW50cyA8LSB0YWJsZShkYXRhJEdlbmRlcikKCiMgQ3JlYXRlIGRhdGEgZnJhbWVzIGZyb20gdGhlIGNvdW50cyBmb3IgZWFjaCBjYXRlZ29yeQpkZWJ0b3JfZGYgPC0gYXMuZGF0YS5mcmFtZShkZWJ0b3JfY291bnRzKQp0dWl0aW9uX2RmIDwtIGFzLmRhdGEuZnJhbWUodHVpdGlvbl9jb3VudHMpCmdlbmRlcl9kZiA8LSBhcy5kYXRhLmZyYW1lKGdlbmRlcl9jb3VudHMpCgojIFJlY29kZSBiaW5hcnkgdmFsdWVzIGZyb20gbnVtYmVycyB0byBjYXRlZ29yaWVzIApkZWJ0b3JfZGYkVmFyMSA8LSByZWNvZGUoZGVidG9yX2RmJFZhcjEsIGAxYCA9ICJEZWJ0IiwgYDBgID0gIk5vIERlYnQiKQp0dWl0aW9uX2RmJFZhcjEgPC0gcmVjb2RlKHR1aXRpb25fZGYkVmFyMSwgYDFgID0gIlBhaWQiLCBgMGAgPSAiVW5wYWlkIikKZ2VuZGVyX2RmJFZhcjEgPC0gcmVjb2RlKGdlbmRlcl9kZiRWYXIxLCBgMWAgPSAiTWFsZSIsIGAwYCA9ICJGZW1hbGUiKQoKIyBDcmVhdGUgdGhlIHBpZSBjaGFydHMgd2l0aCBnZ3Bsb3QyCgojIERlYnRvciBQaWUgQ2hhcnQKcGllX2RlYnRvciA8LSBnZ3Bsb3QoZGVidG9yX2RmLCBhZXMoeCA9ICIiLCB5ID0gRnJlcSwgZmlsbCA9IFZhcjEpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMSkgKyAKICBjb29yZF9wb2xhcih0aGV0YSA9ICJ5IikgKyAgIyBDb252ZXJ0IGJhciBjaGFydCB0byBwaWUgY2hhcnQKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjNEM1N0I4IiwgIiNBRkIxRjAiKSkgKwogIHRoZW1lX3ZvaWQoKSArICAjIFJlbW92ZSBiYWNrZ3JvdW5kIGFuZCBheGVzCiAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQodGl0bGUgPSBOVUxMKSkgKyAgIyBBZGQgbGVnZW5kIGFuZCByZW1vdmUgdGl0bGUKICBnZ3RpdGxlKCJEZWJ0b3IgU3RhdHVzIikgICMgUmVtb3ZlIGluZGl2aWR1YWwgdGl0bGUKCiMgVHVpdGlvbiBGZWVzIFBpZSBDaGFydApwaWVfdHVpdGlvbiA8LSBnZ3Bsb3QodHVpdGlvbl9kZiwgYWVzKHggPSAiIiwgeSA9IEZyZXEsIGZpbGwgPSBWYXIxKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDEpICsgCiAgY29vcmRfcG9sYXIodGhldGEgPSAieSIpICsgICMgQ29udmVydCBiYXIgY2hhcnQgdG8gcGllIGNoYXJ0CiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiI0Y1QTFCNSIsICIjYWMxZjY3IikpICsKICB0aGVtZV92b2lkKCkgKyAgIyBSZW1vdmUgYmFja2dyb3VuZCBhbmQgYXhlcwogIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKHRpdGxlID0gTlVMTCkpICsgICMgQWRkIGxlZ2VuZCBhbmQgcmVtb3ZlIHRpdGxlCiAgZ2d0aXRsZSgiVHVpdGlvbiBGZWVzIikgICMgUmVtb3ZlIGluZGl2aWR1YWwgdGl0bGUKCiMgR2VuZGVyIFBpZSBDaGFydApwaWVfZ2VuZGVyIDwtIGdncGxvdChnZW5kZXJfZGYsIGFlcyh4ID0gIiIsIHkgPSBGcmVxLCBmaWxsID0gVmFyMSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5Iiwgd2lkdGggPSAxKSArIAogIGNvb3JkX3BvbGFyKHRoZXRhID0gInkiKSArICAjIENvbnZlcnQgYmFyIGNoYXJ0IHRvIHBpZSBjaGFydAogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNFNkRFM0MiLCAiI0I5QTUyMCIpKSArCiAgdGhlbWVfdm9pZCgpICsgICMgUmVtb3ZlIGJhY2tncm91bmQgYW5kIGF4ZXMKICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZCh0aXRsZSA9IE5VTEwpKSArICAjIEFkZCBsZWdlbmQgYW5kIHJlbW92ZSB0aXRsZQogIGdndGl0bGUoIkdlbmRlciIpICAKCiMgQ29tYmluZSB0aGUgcGllIGNoYXJ0cyBpbnRvIGEgZ3JpZCB3aXRoIGEgY2VudGVyZWQgbWFpbiB0aXRsZQpncmlkLmFycmFuZ2UoCiAgcGllX2RlYnRvciwgcGllX3R1aXRpb24sIHBpZV9nZW5kZXIsIAogIG5jb2wgPSAzLCAKICBoZWlnaHRzID0gdW5pdChjKDEsIDAuMSksICJucGMiKSAgIyBBbGxvY2F0ZSBzcGFjZSBmb3IgdGhlIGxlZ2VuZHMKKQpgYGAKCiMjIFBhcmVudGFsIEVkdWNhdGlvbgoKVGhpcyBkYXRhc2V0IGNvbnRhaW5zIHRoZSBwcmV2aW91cyBhY2FkZW1pYyBxdWFsaWZpY2F0aW9ucyBvZiB0aGUgc3R1ZGVudCwgbW90aGVyLCBhbmQgZmF0aGVyLiBGb3Igc3R1ZGVudHMsIDg0LjAyJSBoYXZlIGNvbXBsZXRlZCBzZWNvbmRhcnkgZWR1Y2F0aW9uLiBUaGUgcGFyZW50YWwgcXVhbGlmaWNhdGlvbiBkaXN0cmlidXRpb25zIGRvIG5vdCByZWZsZWN0IHRoYXQgb2YgdGhlIHN0dWRlbnRzOiBUaGVyZSBpcyBhIHdpZGVyIHJhbmdlIG9mIGVkdWNhdGlvbmFsIGNhdGVnb3JpZXMgZm9yIGVhY2ggb2YgdGhlIHBhcmVudCBncm91cHMgKGxpa2VseSBkdWUgdG8gdGhlIGRpc3BhcmF0ZSBzb3VyY2VzIG9mIGRhdGEpLiBXaGVuIHJlY29kZWQgYW5kIGdyb3VwZWQgaW50byB0aHJlZSBtYWluIGNhdGVnb3JpZXMgKHNlY29uZGFyeSBlZHVjYXRpb24sIGhpZ2hlciBlZHVjYXRpb24sIGFuZCBvdGhlciksIHRoZSBkaXN0cmlidXRpb24gb2YgcGFyZW50IHF1YWxpZmljYXRpb25zIGluIHRoZSBkYXRhc2V0IGluZGljYXRlcyB0aGF0IG1vc3Qgb2YgdGhlIHBhcmVudCBxdWFsaWZpY2F0aW9ucyBmYWxsIGludG8gdGhlICJvdGhlciIgY2F0ZWdvcnkuIE1vcmUgcmVjb2RpbmcgaXMgcmVxdWlyZWQgdG8gY2xhc3NpZnkgcXVhbGlmaWNhdGlvbnMgaW4gb3JkZXIgdG8gZXhhbWluZSB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gcGFyZW50IHF1YWxpZmljYXRpb24gYW5kIHN0dWRlbnQgZ3JhZGVzLiAKCmBgYHtyIHF1YWxpZmljYXRpb25zfQojIENyZWF0ZSBhIGRhdGFmcmFtZSB3aXRoIDQgcm93cyBhbmQgMzQgY29sdW1ucy4gRmlyc3QgY29sdW1uIGlzIFZhcjEsIDE6MzQKcXVhbCA8LSBkYXRhLmZyYW1lKG1hdHJpeCgxOjM0LCBucm93ID0gMzQsIG5jb2wgPSAxKSkKY29sbmFtZXMocXVhbCkgPC0gYygiVmFyMSIpCgojIENhbGN1bGF0ZSB0aGUgY291bnQgb2YgZWFjaCBjYXRlZ29yeQpTX3F1YWwgPC0gZGF0YS5mcmFtZSh0YWJsZShkYXRhJFNfUXVhbCkpCk1fcXVhbCA8LSBkYXRhLmZyYW1lKHRhYmxlKGRhdGEkTV9RdWFsKSkKRl9xdWFsIDwtIGRhdGEuZnJhbWUodGFibGUoZGF0YSRGX1F1YWwpKQoKIyBNZXJnZSBieSB0aGUgY29tbW9uIGNvbHVtbiAiVmFyMSIKcXVhbCA8LSBtZXJnZShxdWFsLCBTX3F1YWwsIGJ5ID0gIlZhcjEiLCBhbGw9VFJVRSkKcXVhbCA8LSBtZXJnZShxdWFsLCBNX3F1YWwsIGJ5ID0gIlZhcjEiLCBhbGw9VFJVRSkKcXVhbCA8LSBtZXJnZShxdWFsLCBGX3F1YWwsIGJ5ID0gIlZhcjEiLCBhbGw9VFJVRSkKCmNvbG5hbWVzKHF1YWwpIDwtIGMoIlF1YWxpZmljYXRpb24iLCAiU3R1ZGVudCIsICJNb3RoZXIiLCAiRmF0aGVyIikKCiMgUmVwbGFjZSBOQXMgd2l0aCAwCnF1YWxbaXMubmEocXVhbCldIDwtIDAKYGBgCgpgYGB7ciBxdWFsaWZpY2F0aW9uc19wYXJlbnRzfQoKIyBQaXZvdCB0aGUgZGF0YSB0byBsb25nIGZvcm1hdApxdWFsX2xvbmcgPC0gcXVhbCAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IGMoU3R1ZGVudCwgTW90aGVyLCBGYXRoZXIpLCAKICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAiUm9sZSIsIAogICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAiQ291bnQiKQoKIyBGaWx0ZXIgZm9yIG9ubHkgTW90aGVyIGFuZCBGYXRoZXIgcm9sZXMKcXVhbF9sb25nIDwtIHF1YWxfbG9uZyAlPiUKICBmaWx0ZXIoUm9sZSAlaW4lIGMoIk1vdGhlciIsICJGYXRoZXIiKSkKCiMgR3JvdXAgYW5kIHJlbmFtZSB0aGUgJ1F1YWxpZmljYXRpb24nIGNhdGVnb3JpZXMKcXVhbF9sb25nIDwtIHF1YWxfbG9uZyAlPiUKICBtdXRhdGUoUXVhbGlmaWNhdGlvbiA9IGNhc2Vfd2hlbigKICAgIFF1YWxpZmljYXRpb24gPT0gMSB+ICJTZWNvbmRhcnkgRWR1Y2F0aW9uIiwKICAgIFF1YWxpZmljYXRpb24gPj0gMiAmIFF1YWxpZmljYXRpb24gPD0gNiB+ICJIaWdoZXIgRWR1Y2F0aW9uIERlZ3JlZSIsCiAgICBRdWFsaWZpY2F0aW9uID49IDcgJiBRdWFsaWZpY2F0aW9uIDw9IDM0IH4gIk90aGVyIiwKICAgIFRSVUUgfiBhcy5jaGFyYWN0ZXIoUXVhbGlmaWNhdGlvbikgICMgSW4gY2FzZSB0aGVyZSBhcmUgYW55IE5BIG9yIHVucmVjb2duaXplZCB2YWx1ZXMKICApKQoKIyBBZ2dyZWdhdGUgdGhlIGRhdGEgYnkgUXVhbGlmaWNhdGlvbiBhbmQgUm9sZSB0byBnZXQgdG90YWwgY291bnQKcXVhbF9sb25nX2FnZ3JlZ2F0ZWQgPC0gcXVhbF9sb25nICU+JQogIGdyb3VwX2J5KFF1YWxpZmljYXRpb24sIFJvbGUpICU+JQogIHN1bW1hcmlzZShUb3RhbENvdW50ID0gc3VtKENvdW50KSwgLmdyb3VwcyA9ICdkcm9wJykKCiMgQ3JlYXRlIHRoZSBnZ3Bsb3Qgb2JqZWN0IGZvciBzdGFja2VkIGJhciBwbG90CnAgPC0gZ2dwbG90KHF1YWxfbG9uZ19hZ2dyZWdhdGVkLCBhZXMoeCA9IFF1YWxpZmljYXRpb24sIHkgPSBUb3RhbENvdW50LCBmaWxsID0gUm9sZSwgdGV4dCA9IHBhc3RlKCJUb3RhbCBDb3VudDogIiwgVG90YWxDb3VudCkpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsgICMgVXNlIHN0YXQ9ImlkZW50aXR5IiB0byB1c2UgdGhlIGFjdHVhbCBjb3VudHMKICBsYWJzKHggPSAiUXVhbGlmaWNhdGlvbiIsIHkgPSAiQ291bnQiLCBmaWxsID0gIlJvbGUiKSArCiAgZ2d0aXRsZSgiRGlzdHJpYnV0aW9uIG9mIFBhcmVudCBRdWFsaWZpY2F0aW9ucyAoR3JvdXBlZCBieSBFZHVjYXRpb24gTGV2ZWwpIikgKyAgIyBBZGQgdGl0bGUgaGVyZQpzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJNb3RoZXIiID0gIiNGRkMyMEEiLCAiRmF0aGVyIiA9ICIjMEM3QkRDIikpICsgICMgU2V0IGN1c3RvbSBjb2xvcnMKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpCgojIENvbnZlcnQgdGhlIGdncGxvdCBvYmplY3QgdG8gYSBwbG90bHkgb2JqZWN0IGZvciBpbnRlcmFjdGl2aXR5CmludGVyYWN0aXZlX3Bsb3QgPC0gZ2dwbG90bHkocCwgdG9vbHRpcCA9ICJ0ZXh0IikKCiMgU2hvdyB0aGUgaW50ZXJhY3RpdmUgcGxvdAppbnRlcmFjdGl2ZV9wbG90CmBgYAoKCiMjICBHcmFkZSBEaXN0cmlidXRpb24gCgpUaGUgZ3JhZGUgZmVhdHVyZXMgZm9yIGVhY2ggc2VtZXN0ZXIgY29udGFpbiBib3RoIG1pc3NpbmcgdmFsdWVzIGFuZCB2YWx1ZXMgb2YgemVyby4gV2hlbiBncmFkZXMgb2YgemVybyBhcmUgZXhjbHVkZWQsIHRoZSBncmFkZSBkaXN0cmlidXRpb25zIGFyZSBhcHByb3hpbWF0ZWx5IG5vcm1hbGx5IGRpc3RyaWJ1dGVkLiBEYXRhIGltcHV0YXRpb24gY291bGQgcmVwbGFjZSB0aGUgbWlzc2luZyB2YWx1ZXMsIG9yIGFub3RoZXIgYmluYXJ5IGZlYXR1cmUgY2FuIGJlIGNyZWF0ZWQgdG8gcmV0YWluIHRoZSBpbmZvcm1hdGlvbiBvZiBzdHVkZW50cyB3aXRoIGEgZ3JhZGUgb2YgemVybyBmb3IgZWFjaCBzZW1lc3Rlci4KCmBgYHtyIGdyYWRlLWhpc3RvZ3JhbXN9CgojIFJlbW92ZSBncmFkZXMgb2YgemVybwpmaXJzdF9zZW1lc3Rlcl9ncmFkZXMgPC0gZGF0YSRHcmFkZTFbZGF0YSRHcmFkZTEgIT0gMF0Kc2Vjb25kX3NlbWVzdGVyX2dyYWRlcyA8LSBkYXRhJEdyYWRlMltkYXRhJEdyYWRlMiAhPSAwXQoKIyBQbG90IGZvciBmaXJzdCBzZW1lc3RlcgpncmFkZXBsb3QxIDwtIGdncGxvdChkYXRhLmZyYW1lKGdyYWRlID0gZmlyc3Rfc2VtZXN0ZXJfZ3JhZGVzKSwgYWVzKHggPSBncmFkZSkpICsKICBnZW9tX2hpc3RvZ3JhbShhZXMoeSA9IC4uZGVuc2l0eS4uKSwgYmlucyA9IDEwLCBmaWxsID0gIiNhYzFmNjciLCBjb2xvciA9ICJibGFjayIsIGFscGhhID0gMC43KSArCiAgc3RhdF9mdW5jdGlvbihmdW4gPSBkbm9ybSwgYXJncyA9IGxpc3QobWVhbiA9IG1lYW4oZmlyc3Rfc2VtZXN0ZXJfZ3JhZGVzKSwgc2QgPSBzZChmaXJzdF9zZW1lc3Rlcl9ncmFkZXMpKSwgY29sb3IgPSAicmVkIiwgc2l6ZSA9IDEpICsKICBsYWJzKHRpdGxlID0gIkZpcnN0IFNlbWVzdGVyIEdyYWRlcyIsIHggPSAiR3JhZGVzIiwgeSA9ICJEZW5zaXR5IikgKwogIHRoZW1lX21pbmltYWwoKQoKIyBQbG90IGZvciBzZWNvbmQgc2VtZXN0ZXIKZ3JhZGVwbG90MiA8LSBnZ3Bsb3QoZGF0YS5mcmFtZShncmFkZSA9IHNlY29uZF9zZW1lc3Rlcl9ncmFkZXMpLCBhZXMoeCA9IGdyYWRlKSkgKwogIGdlb21faGlzdG9ncmFtKGFlcyh5ID0gLi5kZW5zaXR5Li4pLCBiaW5zID0gMTAsIGZpbGwgPSAiI2FjMWY2NyIsIGNvbG9yID0gImJsYWNrIiwgYWxwaGEgPSAwLjcpICsKICBzdGF0X2Z1bmN0aW9uKGZ1biA9IGRub3JtLCBhcmdzID0gbGlzdChtZWFuID0gbWVhbihzZWNvbmRfc2VtZXN0ZXJfZ3JhZGVzKSwgc2QgPSBzZChzZWNvbmRfc2VtZXN0ZXJfZ3JhZGVzKSksIGNvbG9yID0gImJsdWUiLCBzaXplID0gMSkgKwogIGxhYnModGl0bGUgPSAiU2Vjb25kIFNlbWVzdGVyIEdyYWRlcyIsIHggPSAiR3JhZGVzIiwgeSA9ICJEZW5zaXR5IikgKwogIHRoZW1lX21pbmltYWwoKQoKIyBBcnJhbmdlIHRoZSB0d28gcGxvdHMgc2lkZSBieSBzaWRlCmdyaWQuYXJyYW5nZShncmFkZXBsb3QxLCBncmFkZXBsb3QyLCBuY29sID0gMikKYGBgCgojICBSZWxhdGlvbnNoaXAgQmV0d2VlbiBGZWF0dXJlcwoKVGhpcyBzZWN0aW9uIGV4YW1pbmVzIHRoZSByZWxhdGlvbnNoaXBzIGJldHdlZW4ga2V5IGNhdGVnb3JpY2FsIGFuZCBudW1lcmljYWwgZmVhdHVyZXMgaW4gdGhlIGRhdGFzZXQuIAoKIyMgR3JhZGUgQXZlcmFnZXMgCgpHcmFkZSBhdmVyYWdlIGluIHRoZSBmaXJzdCBzZW1lc3RlciBhbmQgc2Vjb25kIHNlbWVzdGVyIGFwcGVhciB0byBoYXZlIGEgcG9zaXRpdmUgbGluZWFyIHJlbGF0aW9uc2hpcC4gQmFzZWQgb24gdGhpcyBtb2RlbCwgZm9yIGV2ZXJ5IG9uZS11bml0IGluY3JlYXNlIGluIGZpcnN0IHNlbWVzdGVyIGdyYWRlIGF2ZXJhZ2UsIHdlIGV4cGVjdCB0byBzZWUgYSAwLjcgaW5jcmVhc2UgaW4gc2Vjb25kLXNlbWVzdGVyIGdyYWRlIGF2ZXJhZ2UuIAoKYGBge3IgZ3JhZGVzfQojIFJlbW92ZSByb3dzIHdoZXJlIEdyYWRlMSBvciBHcmFkZTIgaXMgemVybwpmaWx0ZXJlZF9kYXRhIDwtIGRhdGFbZGF0YSRHcmFkZTEgIT0gMCAmIGRhdGEkR3JhZGUyICE9IDAsIF0KCiMgRml0IGEgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwKbW9kZWwgPC0gbG0oR3JhZGUyIH4gR3JhZGUxLCBkYXRhID0gZmlsdGVyZWRfZGF0YSkKCiMgU2NhdHRlcnBsb3Qgb2YgZmlyc3Qtc2VtZXN0ZXIgYW5kIHNlY29uZC1zZW1lc3RlciBhdmVyYWdlIGdyYWRlcwpwbG90KGZpbHRlcmVkX2RhdGEkR3JhZGUxLCBmaWx0ZXJlZF9kYXRhJEdyYWRlMiwKICAgICBjb2wgPSAiI0ZGQzIwQSIsCiAgICAgcGNoID0gMTksIAogICAgIG1haW4gPSAiQXZlcmFnZSBHcmFkZXMiLAogICAgIHhsYWIgPSAiRmlyc3QgU2VtZXN0ZXIiLAogICAgIHlsYWIgPSAiU2Vjb25kIFNlbWVzdGVyIikKCiMgQWRkIHRoZSByZWdyZXNzaW9uIGxpbmUKYWJsaW5lKG1vZGVsLCBjb2wgPSAiYmxhY2siLCBsd2QgPSAyKSAgIyBSZWQgcmVncmVzc2lvbiBsaW5lIHdpdGggdGhpY2tuZXNzIG9mIDIKCiMgY29lZmZpY2llbnQgb2YgR3JhZGUxCnNsb3BlIDwtIGNvZWYobW9kZWwpWzJdCmBgYAoKIyMgIEdyYWRlcyBhbmQgRmluYW5jZXMKCkEgbWlub3JpdHkgb2Ygc3R1ZGVudHMgaGF2ZSBkZWJ0IG9yIHVucGFpZCB0dWl0aW9uIGZlZXMuIEluIHRoZSBmaWd1cmUgYmVsb3csIHRoZSBkaXN0cmlidXRpb24gb2YgYXZlcmFnZSBncmFkZXMgaXMgc3RyYXRpZmllZCBieSBkZWJ0IHN0YXR1cyBhbmQgYWxzbyBieSB0dWl0aW9uIHN0YXR1cy4gVGhlIHN0dWRlbnRzIGluIHRoZSBtaW5vcml0eSBmb3IgdGhlc2UgY2F0ZWdvcmllcyBhcHBlYXIgdG8gaGF2ZSBhIGxvd2VyIGdyYWRlIGRpc3RyaWJ1dGlvbi4gQXQgdGhlIDAuMDUgc2lnbmlmaWNhbmNlIGxldmVsLCB0aGVyZSBpcyBzdWZmaWNpZW50IGV2aWRlbmNlIHRvIGNvbmNsdWRlIHRoYXQgdGhlIG1lYW4gYXZlcmFnZSBncmFkZXMgZGlmZmVyIHNpZ25pZmljYW50bHkgYmV0d2VlbiB0aGVzZSBtYWpvcml0eSBhbmQgbWlub3JpdHkgZ3JvdXBzLiBBbmFseXRpYyB0YXNrcyB3aWxsIGluY2x1ZGUgcmVtb3Zpbmcgb3IgaW1wdXRhdGluZyBncmFkZSB2YWx1ZXMgb2YgemVybywgdGhlbiByZS1leGFtaW5pbmcgdGhlIHJlbGF0aW9uc2hpcC4gCgoKIyMjIyBEaXN0cmlidXRpb24gb2YgQXZlcmFnZSBHcmFkZXMgYnkgRGVidG9yIFN0YXR1cwpgYGB7ciBib3hwbG90ZGVidH0KY29sMCA9IGMoIiNGRkMyMEEiLCAiIzBDN0JEQyIpCgojIFNldCB1cCBsYXlvdXQgZm9yIHRoZSBib3hwbG90cwpwYXIobWZyb3cgPSBjKDEsIDIpKSAgIyAxIHJvd3MsIDIgY29sdW1ucwoKIyBDcmVhdGUgdHdvIGJveHBsb3RzCmJveHBsb3QoZGF0YSRHcmFkZTEgfiBkYXRhJERlYnRvciwgCiAgICAgICAgY29sID0gYygiI0ZGQzIwQSIsICIjMEM3QkRDIiksCiAgICAgICAgbWFpbiA9ICJGaXJzdCBTZW1lc3RlciIsCiAgICAgICAgeGxhYiA9ICIgIiwKICAgICAgICB5bGFiID0gIkF2ZXJhZ2UgR3JhZGUiLAogICAgICAgIGNleC5heGlzID0gMC45LCAgIyBTbWFsbGVyIGZvbnQgc2l6ZSBmb3IgYXhpcyBsYWJlbHMKICAgICAgICBjZXgubGFiID0gMC45KSAgICMgU21hbGxlciBmb250IHNpemUgZm9yIGF4aXMgdGl0bGVzCgpib3hwbG90KGRhdGEkR3JhZGUyIH4gZGF0YSREZWJ0b3IsCiAgICAgICAgY29sID0gYygiI0ZGQzIwQSIsICIjMEM3QkRDIiksCiAgICAgICAgbWFpbiA9ICJTZWNvbmQgU2VtZXN0ZXIiLAogICAgICAgIHhsYWIgPSAiICIsCiAgICAgICAgeWxhYiA9ICIgIiwKICAgICAgICBjZXguYXhpcyA9IDAuOSwgICMgU21hbGxlciBmb250IHNpemUgZm9yIGF4aXMgbGFiZWxzCiAgICAgICAgY2V4LmxhYiA9IDAuOSkgICAjIFNtYWxsZXIgZm9udCBzaXplIGZvciBheGlzIHRpdGxlcwpgYGAKCiMjIyMgRGlzdHJpYnV0aW9uIG9mIEF2ZXJhZ2UgR3JhZGVzIGJ5IFR1aXRpb24gU3RhdHVzCmBgYHtyIGJveHBsb3R0dWl0aW9ufQoKY29sMSA9IGMoIiMwQzdCREMiLCAiI0ZGQzIwQSIpCgojIFNldCB1cCBsYXlvdXQgZm9yIHRoZSBib3hwbG90cwpwYXIobWZyb3cgPSBjKDEsIDIpKSAgIyAxIHJvd3MsIDIgY29sdW1ucwoKYm94cGxvdChkYXRhJEdyYWRlMSB+IGRhdGEkVHVpdGlvbiwgCiAgICAgICAgY29sID0gY29sMSwKICAgICAgICBtYWluID0gIkZpcnN0IFNlbWVzdGVyIiwKICAgICAgICB4bGFiID0gIiAiLAogICAgICAgIHlsYWIgPSAiQXZlcmFnZSBHcmFkZSIsCiAgICAgICAgY2V4LmF4aXMgPSAwLjksICAjIFNtYWxsZXIgZm9udCBzaXplIGZvciBheGlzIGxhYmVscwogICAgICAgIGNleC5sYWIgPSAwLjkpICAgIyBTbWFsbGVyIGZvbnQgc2l6ZSBmb3IgYXhpcyB0aXRsZXMKYm94cGxvdChkYXRhJEdyYWRlMiB+IGRhdGEkVHVpdGlvbiwgCiAgICAgICAgY29sID0gY29sMSwKICAgICAgICBtYWluID0gIlNlY29uZCBTZW1lc3RlciIsCiAgICAgICAgeGxhYiA9ICIgIiwKICAgICAgICB5bGFiID0gIiAiLAogICAgICAgIGNleC5heGlzID0gMC45LCAgIyBTbWFsbGVyIGZvbnQgc2l6ZSBmb3IgYXhpcyBsYWJlbHMKICAgICAgICBjZXgubGFiID0gMC45KSAgICMgU21hbGxlciBmb250IHNpemUgZm9yIGF4aXMgdGl0bGVzCmBgYAoKYGBge3IgdHRlc3RfRGVidH0KIyBUIHRlc3QgYmV0d2VlbiBjYXRlZ29yaWNhbCB2YXJpYWJsZSBhbmQgY29udGludW91cyB2YXJpYWJsZQppbnZpc2libGUodC50ZXN0KGRhdGEkR3JhZGUxIH4gZGF0YSREZWJ0b3IsIGRhdGEgPSBkYXRhKSkKaW52aXNpYmxlKHQudGVzdChkYXRhJEdyYWRlMiB+IGRhdGEkRGVidG9yLCBkYXRhID0gZGF0YSkpCmBgYAoKYGBge3IgdHRlc3RfdHVpdGlvbn0KIyBUIHRlc3QgYmV0d2VlbiBjYXRlZ29yaWNhbCB2YXJpYWJsZSBhbmQgY29udGludW91cyB2YXJpYWJsZQppbnZpc2libGUodC50ZXN0KGRhdGEkR3JhZGUxIH4gZGF0YSRUdWl0aW9uLCBkYXRhID0gZGF0YSkpCmludmlzaWJsZSh0LnRlc3QoZGF0YSRHcmFkZTIgfiBkYXRhJFR1aXRpb24sIGRhdGEgPSBkYXRhKSkKYGBgCgojIyBHcmFkZXMgYW5kIEdlbmRlcgoKTWFsZSBzdHVkZW50cywgYWNjb3VudGluZyBmb3IgMzUuMTclIG9mIHRoZSBkYXRhc2V0LCBhcHBlYXIgdG8gYWNoaWV2ZSBhIGxvd2VyIGF2ZXJhZ2UgZ3JhZGUgZGlzdHJpYnV0aW9uLiBUaGVyZSBpcyBlbm91Z2ggZXZpZGVuY2UgdG8gaW5kaWNhdGUgYSBzaWduaWZpY2FudCBkaWZmZXJlbmNlIGJldHdlZW4gdGhpcyBncm91cCdzIG1lYW4gYXZlcmFnZSBncmFkZSBhbmQgdGhhdCBvZiBmZW1hbGUgc3R1ZGVudHMgYXQgdGhlIDAuMDUgc2lnbmlmaWNhbmNlIGxldmVsLiBBbmFseXRpYyB0YXNrcyB3aWxsIGluY2x1ZGUgcmVtb3Zpbmcgb3IgaW1wdXRhdGluZyBncmFkZSB2YWx1ZXMgb2YgemVybywgdGhlbiByZS1leGFtaW5pbmcgdGhlIHJlbGF0aW9uc2hpcC4gCgoKIyMjIyBEaXN0cmlidXRpb24gb2YgQXZlcmFnZSBHcmFkZXMgYnkgR2VuZGVyCmBgYHtyIGJveHBsb3RnZW5kZXJ9Cgpjb2wxID0gYygiIzBDN0JEQyIsICIjRkZDMjBBIikKCiMgU2V0IHVwIGxheW91dCBmb3IgdGhlIGJveHBsb3RzCnBhcihtZnJvdyA9IGMoMSwgMikpICAjIDEgcm93cywgMiBjb2x1bW5zCgpib3hwbG90KGRhdGEkR3JhZGUxIH4gZGF0YSRHZW5kZXIsIAogICAgICAgIGNvbCA9IGNvbDEsCiAgICAgICAgbWFpbiA9ICJGaXJzdCBTZW1lc3RlciIsCiAgICAgICAgeGxhYiA9ICIgIiwKICAgICAgICB5bGFiID0gIkF2ZXJhZ2UgR3JhZGUiLAogICAgICAgIGNleC5heGlzID0gMC45LCAgIyBTbWFsbGVyIGZvbnQgc2l6ZSBmb3IgYXhpcyBsYWJlbHMKICAgICAgICBjZXgubGFiID0gMC45KSAgICMgU21hbGxlciBmb250IHNpemUgZm9yIGF4aXMgdGl0bGVzCmJveHBsb3QoZGF0YSRHcmFkZTIgfiBkYXRhJEdlbmRlciwgCiAgICAgICAgY29sID0gY29sMSwKICAgICAgICBtYWluID0gIlNlY29uZCBTZW1lc3RlciIsCiAgICAgICAgeGxhYiA9ICIgIiwKICAgICAgICB5bGFiID0gIiAiLAogICAgICAgIGNleC5heGlzID0gMC45LCAgIyBTbWFsbGVyIGZvbnQgc2l6ZSBmb3IgYXhpcyBsYWJlbHMKICAgICAgICBjZXgubGFiID0gMC45KSAgICMgU21hbGxlciBmb250IHNpemUgZm9yIGF4aXMgdGl0bGVzCmBgYAoKYGBge3IgdHRlc3RfZ2VuZGVyfQojIFQgdGVzdCBiZXR3ZWVuIGNhdGVnb3JpY2FsIHZhcmlhYmxlIGFuZCBjb250aW51b3VzIHZhcmlhYmxlCmludmlzaWJsZSh0LnRlc3QoZGF0YSRHcmFkZTEgfiBkYXRhJEdlbmRlciwgZGF0YSA9IGRhdGEpKQppbnZpc2libGUodC50ZXN0KGRhdGEkR3JhZGUyIH4gZGF0YSRHZW5kZXIsIGRhdGEgPSBkYXRhKSkKYGBgCgojIyBDdXJyaWN1bGFyIFVuaXRzIAoKVGhpcyBkYXRhc2V0IGluY2x1ZGVzIG11bHRpcGxlIHZhcmlhYmxlcyBtZWFzdXJpbmcgY3JlZGl0cyBmb3IgZWFjaCBzZW1lc3RlcjogbnVtYmVyIG9mIGN1cnJpY3VsYXIgdW5pdHMgY3JlZGl0ZWQsIGVucm9sbGVkLCBhbmQgYXBwcm92ZWQuIEEgc2lnbmlmaWNhbnQgbnVtYmVyIG9mIHRoZSBjcmVkaXRlZCB2YXJpYWJsZXMgZm9yIGVhY2ggc2VtZXN0ZXIgaGF2ZSBhIHZhbHVlIG9mIHplcm8sIG1vcmUgc28gaW4gdGhlIHNlY29uZCBzZW1lc3RlcjsgdGhpcyBtYXkgaW5kaWNhdGUgdGhhdCB0aGUgaW5mb3JtYXRpb24gd2FzIHJlY29yZGVkIGJlZm9yZSB0aGUgZW5kIG9mIHRoZSBzZWNvbmQgc2VtZXN0ZXIgYW5kIG1heSBiZSBpbmNvbXBsZXRlLiBGb3IgdGhpcyByZWFzb24sIHdlIG1pZ2h0IGNvbnNpZGVyIG9ubHkgaW5jbHVkaW5nIGFwcHJvdmVkIGN1cnJpY3VsYXIgdW5pdHMgYXMgYSBwb3RlbnRpYWwgdmFyaWFibGUgaW4gb3VyIG1vZGVsLiAKCmBgYHtyIGNyZWRpdF9ieV9zZW1lc3RlcjF9CnNlbTFfYXBwcm92ZWQgPC0gZGF0YSRVX0FwcHJvdmVkMQpzZW0xX2Vucm9sbGVkIDwtIGRhdGEkVV9FbnJvbGxlZDEKc2VtMV9jcmVkaXRlZCA8LSBkYXRhJFVfQ3JlZGl0ZWQxCgojIENvdW50IGZyZXF1ZW5jaWVzIG9mIGNyZWRpdHMgZm9yIGVhY2ggdmFyaWFibGUgZm9yIHRoZSBmaXJzdCBzZW1lc3RlcgpzZW0xX2FwcHJvdmVkX2NvdW50cyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHNlbTFfYXBwcm92ZWQpKQpzZW0xX2Vucm9sbGVkX2NvdW50cyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHNlbTFfZW5yb2xsZWQpKQpzZW0xX2NyZWRpdGVkX2NvdW50cyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHNlbTFfY3JlZGl0ZWQpKQoKIyBDcmVhdGUgYmFyIHBsb3RzIGZvciB0aGUgZmlyc3Qgc2VtZXN0ZXIKcGxvdDEgPC0gZ2dwbG90KHNlbTFfYXBwcm92ZWRfY291bnRzLCBhZXMoeCA9IHNlbTFfYXBwcm92ZWQsIHkgPSBGcmVxKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gIiNhYzFmNjciLCBjb2xvciA9ICJibGFjayIsIGFscGhhID0gMC43KSArCiAgbGFicyh0aXRsZSA9ICIgIiwgeCA9ICJDcmVkaXRzIEFwcHJvdmVkIiwgeSA9ICJOdW1iZXIgb2YgT2NjdXJyZW5jZXMiKSArICAKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKQoKcGxvdDIgPC0gZ2dwbG90KHNlbTFfZW5yb2xsZWRfY291bnRzLCBhZXMoeCA9IHNlbTFfZW5yb2xsZWQsIHkgPSBGcmVxKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gIiMwQzdCREMiLCBjb2xvciA9ICJibGFjayIsIGFscGhhID0gMC43KSArCiAgbGFicyh0aXRsZSA9ICJGaXJzdCBTZW1lc3RlciIsIHggPSAiQ3JlZGl0cyBFbnJvbGxlZCIsIHkgPSAiICIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKQoKcGxvdDMgPC0gZ2dwbG90KHNlbTFfY3JlZGl0ZWRfY291bnRzLCBhZXMoeCA9IHNlbTFfY3JlZGl0ZWQsIHkgPSBGcmVxKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gIiNGRkMyMEEiLCBjb2xvciA9ICJibGFjayIsIGFscGhhID0gMC43KSArCiAgbGFicyh0aXRsZSA9ICIgIiwgeCA9ICJDcmVkaXRlZCBVbml0cyIsIHkgPSAiICIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKQoKIyBBcnJhbmdlIHRoZSBwbG90cyBzaWRlIGJ5IHNpZGUgZm9yIHRoZSBmaXJzdCBzZW1lc3RlcgpncmlkLmFycmFuZ2UocGxvdDEsIHBsb3QyLCBwbG90MywgbmNvbCA9IDMpCmBgYAoKYGBge3IgY3JlZGl0X2J5X3NlbWVzdGVyMn0Kc2VtMl9hcHByb3ZlZCA8LSBkYXRhJFVfQXBwcm92ZWQyCnNlbTJfZW5yb2xsZWQgPC0gZGF0YSRVX0Vucm9sbGVkMgpzZW0yX2NyZWRpdGVkIDwtIGRhdGEkVV9DcmVkaXRlZDIKCiMgQ291bnQgZnJlcXVlbmNpZXMgb2YgY3JlZGl0cyBmb3IgZWFjaCB2YXJpYWJsZSBmb3IgdGhlIHNlY29uZCBzZW1lc3RlcgpzZW0yX2FwcHJvdmVkX2NvdW50cyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHNlbTJfYXBwcm92ZWQpKQpzZW0yX2Vucm9sbGVkX2NvdW50cyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHNlbTJfZW5yb2xsZWQpKQpzZW0yX2NyZWRpdGVkX2NvdW50cyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHNlbTJfY3JlZGl0ZWQpKQoKIyBDcmVhdGUgYmFyIHBsb3RzIGZvciB0aGUgc2Vjb25kIHNlbWVzdGVyCnBsb3QxXzJuZCA8LSBnZ3Bsb3Qoc2VtMl9hcHByb3ZlZF9jb3VudHMsIGFlcyh4ID0gc2VtMl9hcHByb3ZlZCwgeSA9IEZyZXEpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAiI2FjMWY2NyIsIGNvbG9yID0gImJsYWNrIiwgYWxwaGEgPSAwLjcpICsKICBsYWJzKHRpdGxlID0gIiAiLCB4ID0gIkNyZWRpdHMgQXBwcm92ZWQiLCB5ID0gIk51bWJlciBvZiBPY2N1cnJlbmNlcyIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKQoKcGxvdDJfMm5kIDwtIGdncGxvdChzZW0yX2Vucm9sbGVkX2NvdW50cywgYWVzKHggPSBzZW0yX2Vucm9sbGVkLCB5ID0gRnJlcSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICIjMEM3QkRDIiwgY29sb3IgPSAiYmxhY2siLCBhbHBoYSA9IDAuNykgKwogIGxhYnModGl0bGUgPSAiU2Vjb25kIFNlbWVzdGVyIiwgeCA9ICJDcmVkaXRzIEVucm9sbGVkIiwgeSA9ICIgIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCkpCgpwbG90M18ybmQgPC0gZ2dwbG90KHNlbTJfY3JlZGl0ZWRfY291bnRzLCBhZXMoeCA9IHNlbTJfY3JlZGl0ZWQsIHkgPSBGcmVxKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gIiNGRkMyMEEiLCBjb2xvciA9ICJibGFjayIsIGFscGhhID0gMC43KSArCiAgbGFicyh0aXRsZSA9ICIgIiwgeCA9ICJDcmVkaXRlZCBVbml0cyIsIHkgPSAiICIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKQoKIyBBcnJhbmdlIHRoZSBwbG90cyBzaWRlIGJ5IHNpZGUgZm9yIHRoZSBzZWNvbmQgc2VtZXN0ZXIKZ3JpZC5hcnJhbmdlKHBsb3QxXzJuZCwgcGxvdDJfMm5kLCBwbG90M18ybmQsIG5jb2wgPSAzKQpgYGAKCgojIyBTdHJhdGlmeWluZyBHcmFkZXMgYnkgQ3VycmljdWxhciBVbml0IEdyb3VwCgpCYXNlZCBvbiB0aGUgYm94cGxvdHMgZm9yIGdyYWRlcyBzdHJhdGlmaWVkIGJ5IHRoZSBjdXJyaWN1bGFyIHVuaXQgYXBwcm92ZWQgZ3JvdXAsIGl0IGFwcGVhcnMgdGhhdCBzdHVkZW50cyB3aXRoIGJldHdlZW4gNCBhbmQgOCBjdXJyaWN1bGFyIHVuaXRzIGFwcHJvdmVkIGFjaGlldmUgc2lnbmlmaWNhbnRseSBoaWdoZXIgZ3JhZGVzIHRoYW4gdGhvc2Ugd2l0aCBmZXdlciB0aGFuIDQgYW5kIHNsaWdodGx5IGhpZ2hlciBncmFkZXMgb24gYXZlcmFnZSB0aGFuIHRob3NlIG1vcmUgdGhhbiA4LiAKCgpgYGB7ciBjcmVkaXRzX2FwcHJvdmVkX2dyb3VwZWR9CiMgQ3JlYXRlIFVuaXRfR3JvdXAxIGJhc2VkIG9uIFVfQXBwcm92ZWQxCmRhdGEkVW5pdF9Hcm91cDEgPC0gY3V0KGRhdGEkVV9BcHByb3ZlZDEsIAogICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBjKC1JbmYsIDAsIDMsIDgsIEluZiksIAogICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCIwIiwgIjEtMyIsICI0LTgiLCAiOSsiKSwKICAgICAgICAgICAgICAgICAgICAgICAgcmlnaHQgPSBUUlVFKQoKIyBDcmVhdGUgVW5pdF9Hcm91cDIgYmFzZWQgb24gVV9BcHByb3ZlZDIKZGF0YSRVbml0X0dyb3VwMiA8LSBjdXQoZGF0YSRVX0FwcHJvdmVkMiwgCiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGMoLUluZiwgMCwgMywgOCwgSW5mKSwgCiAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIjAiLCAiMS0zIiwgIjQtOCIsICI5KyIpLAogICAgICAgICAgICAgICAgICAgICAgICByaWdodCA9IFRSVUUpCmBgYAoKYGBge3IgZ3JhZGVfY3JlZGl0c19ib3hwbG90fQpjb2wyID0gYygiI0ZGQzIwQSIsICIjMEM3QkRDIiwgIiNhYzFmNjciKQoKIyBGaWx0ZXIgb3V0ICIwIiBncm91cCBmcm9tIGJvdGggVW5pdF9Hcm91cDEgYW5kIFVuaXRfR3JvdXAyCmRhdGFfZmlsdGVyZWQxIDwtIGRhdGFbZGF0YSRVbml0X0dyb3VwMSAhPSAiMCIsIF0KZGF0YV9maWx0ZXJlZDIgPC0gZGF0YVtkYXRhJFVuaXRfR3JvdXAyICE9ICIwIiwgXQoKIyBTZXQgdXAgbGF5b3V0IGZvciB0aGUgYm94cGxvdHMKcGFyKG1mcm93ID0gYygxLCAyKSkgICMgMSByb3csIDIgY29sdW1ucwoKIyBDcmVhdGUgdGhlIGZpcnN0IGJveHBsb3QgZm9yIHRoZSBmaXJzdCBzZW1lc3RlciwgZXhjbHVkaW5nICIwIiBncm91cApib3hwbG90KGRhdGFfZmlsdGVyZWQxJEdyYWRlMSB+IGRhdGFfZmlsdGVyZWQxJFVuaXRfR3JvdXAxLCAKICAgICAgICBjb2wgPSBjb2wyLAogICAgICAgIG1haW4gPSAiRmlyc3QgU2VtZXN0ZXIiLAogICAgICAgIHhsYWIgPSAiICIsCiAgICAgICAgeWxhYiA9ICJBdmVyYWdlIEdyYWRlIiwKICAgICAgICBjZXguYXhpcyA9IDAuOSwgICMgU21hbGxlciBmb250IHNpemUgZm9yIGF4aXMgbGFiZWxzCiAgICAgICAgY2V4LmxhYiA9IDAuOSkgICAjIFNtYWxsZXIgZm9udCBzaXplIGZvciBheGlzIHRpdGxlcwoKIyBDcmVhdGUgdGhlIHNlY29uZCBib3hwbG90IGZvciB0aGUgc2Vjb25kIHNlbWVzdGVyLCBleGNsdWRpbmcgIjAiIGdyb3VwCmJveHBsb3QoZGF0YV9maWx0ZXJlZDIkR3JhZGUyIH4gZGF0YV9maWx0ZXJlZDIkVW5pdF9Hcm91cDIsCiAgICAgICAgY29sID0gY29sMiwKICAgICAgICBtYWluID0gIlNlY29uZCBTZW1lc3RlciIsCiAgICAgICAgeGxhYiA9ICIgIiwKICAgICAgICB5bGFiID0gIiAiLAogICAgICAgIGNleC5heGlzID0gMC45LCAgIyBTbWFsbGVyIGZvbnQgc2l6ZSBmb3IgYXhpcyBsYWJlbHMKICAgICAgICBjZXgubGFiID0gMC45KSAgICMgU21hbGxlciBmb250IHNpemUgZm9yIGF4aXMgdGl0bGVzCmBgYAoKTm90ZSBhIHNpbWlsYXIgdHJlbmQgZm9yIHRoZSBudW1iZXIgb2YgZXZhbHVhdGlvbnMgdG8gY3VycmljdWxhciB1bml0cy4gCgpgYGB7ciBldmFsX2dyb3VwZWR9CiMgQ3JlYXRlIEV2YWxfR3JvdXAxIGJhc2VkIG9uIFVfRXZhbHVhdGVkMQpkYXRhJEV2YWxfR3JvdXAxIDwtIGN1dChkYXRhJFVfRXZhbHVhdGVkMSwgCiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGMoLUluZiwgMCwgNCwgMTAsIEluZiksIAogICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCIwIiwgIjEtNCIsICI1LTEwIiwgIjExKyIpLAogICAgICAgICAgICAgICAgICAgICAgICByaWdodCA9IFRSVUUpCgojIENyZWF0ZSBFdmFsX0dyb3VwMiBiYXNlZCBvbiBVX0V2YWx1YXRlZDIKZGF0YSRFdmFsX0dyb3VwMiA8LSBjdXQoZGF0YSRVX0V2YWx1YXRlZDIsIAogICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBjKC1JbmYsIDAsIDQsIDEwLCBJbmYpLCAKICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiMCIsICIxLTQiLCAiNS0xMCIsICIxMSsiKSwKICAgICAgICAgICAgICAgICAgICAgICAgcmlnaHQgPSBUUlVFKQpgYGAKCmBgYHtyIGdyYWRlX2V2YWxfYm94cGxvdH0KY29sMyA9IGMoIiNGRkMyMEEiLCAiIzBDN0JEQyIsICIjYWMxZjY3IiwgIiNBRkIxRjAiKQoKIyBTZXQgdXAgbGF5b3V0IGZvciB0aGUgYm94cGxvdHMKcGFyKG1mcm93ID0gYygxLCAyKSkgICMgMSByb3csIDIgY29sdW1ucwoKIyBDcmVhdGUgdGhlIGZpcnN0IGJveHBsb3QgZm9yIHRoZSBmaXJzdCBzZW1lc3Rlcgpib3hwbG90KGRhdGEkR3JhZGUxIH4gZGF0YSRFdmFsX0dyb3VwMSwgCiAgICAgICAgY29sID0gY29sMywKICAgICAgICBtYWluID0gIkZpcnN0IFNlbWVzdGVyIiwKICAgICAgICB4bGFiID0gIkV2YWx1YXRpb25zIiwKICAgICAgICB5bGFiID0gIkF2ZXJhZ2UgR3JhZGUiLAogICAgICAgIGNleC5heGlzID0gMC45LCAgIyBTbWFsbGVyIGZvbnQgc2l6ZSBmb3IgYXhpcyBsYWJlbHMKICAgICAgICBjZXgubGFiID0gMC45KSAgICMgU21hbGxlciBmb250IHNpemUgZm9yIGF4aXMgdGl0bGVzCgojIENyZWF0ZSB0aGUgc2Vjb25kIGJveHBsb3QgZm9yIHRoZSBzZWNvbmQgc2VtZXN0ZXIKYm94cGxvdChkYXRhJEdyYWRlMiB+IGRhdGEkRXZhbF9Hcm91cDIsCiAgICAgICAgY29sID0gY29sMywKICAgICAgICBtYWluID0gIlNlY29uZCBTZW1lc3RlciIsCiAgICAgICAgeGxhYiA9ICIgIiwKICAgICAgICB5bGFiID0gIiAiLAogICAgICAgIGNleC5heGlzID0gMC45LCAgIyBTbWFsbGVyIGZvbnQgc2l6ZSBmb3IgYXhpcyBsYWJlbHMKICAgICAgICBjZXgubGFiID0gMC45KSAgICMgU21hbGxlciBmb250IHNpemUgZm9yIGF4aXMgdGl0bGVzCmBgYAoKCiMgIFJlZmVyZW5jZXMgCgoqKkRBVEEqKjogTS5WLk1hcnRpbnMsIEQuIFRvbGxlZG8sIEouIE1hY2hhZG8sIEwuIE0uVC4gQmFwdGlzdGEsIFYuUmVhbGluaG8uICgyMDIxKS4gUHJlZGljdCBTdHVkZW50cycgRHJvcG91dCBhbmQgQWNhZGVtaWMgU3VjY2Vzcy4gS2FnZ2xlLiBBdHRyaWJ1dGlvbiA0LjAgSW50ZXJuYXRpb25hbCAoQ0MgQlkgNC4wKS4gaHR0cHM6Ly93d3cua2FnZ2xlLmNvbS9kYXRhc2V0cy9oYXJzaGl0c3JpdmFzdGF2YTI1L3ByZWRpY3Qtc3R1ZGVudHMtZHJvcG91dC1hbmQtYWNhZGVtaWMtc3VjY2Vzcy9kYXRhIA==